diff --git a/.gitignore b/.gitignore index f8005ca0..7f15a9d0 100644 --- a/.gitignore +++ b/.gitignore @@ -1,22 +1,22 @@ -*.suo -*.sln -*.vcxproj -*.filters -*.user -*.pdb -*.db -*.psess -*.opendb -*.opensdf -*.sdf -*.suo -*.vspx -*.xcodeproj -build -debug -release -ipch -Makefile -library.bin -leocad_plugin_import.cpp -*.qm +*.suo +*.sln +*.vcxproj +*.filters +*.user +*.pdb +*.db +*.psess +*.opendb +*.opensdf +*.sdf +*.suo +*.vspx +*.xcodeproj +build +debug +release +ipch +Makefile +library.bin +leocad_plugin_import.cpp +*.qm diff --git a/common/lc_array.h b/common/lc_array.h index 7b4336c7..782955af 100644 --- a/common/lc_array.h +++ b/common/lc_array.h @@ -1,251 +1,251 @@ -#ifndef _LC_ARRAY_H_ -#define _LC_ARRAY_H_ - -template -class lcArray -{ -public: - typedef int (*lcArrayCompareFunc)(const T& a, const T& b); - - lcArray(int Size = 0, int Grow = 16) - { - mData = NULL; - mLength = 0; - mAlloc = 0; - mGrow = Grow; - - if (Size != 0) - AllocGrow(Size); - } - - lcArray(const lcArray& Array) - { - mData = NULL; - *this = Array; - } - - ~lcArray() - { - delete[] mData; - } - - lcArray& operator=(const lcArray& Array) - { - mLength = Array.mLength; - mAlloc = Array.mAlloc; - mGrow = Array.mGrow; - - delete[] mData; - mData = new T[mAlloc]; - - for (int i = 0; i < mLength; i++) - mData[i] = Array.mData[i]; - - return *this; - } - - lcArray& operator+=(const lcArray& Array) - { - AllocGrow(Array.mLength); - - for (int i = 0; i < Array.mLength; i++) - mData[mLength + i] = Array.mData[i]; - - mLength += Array.mLength; - return *this; - } - - const T& operator[](int Index) const - { - return mData[Index]; - } - - T& operator[](int Index) - { - return mData[Index]; - } - - bool operator==(const lcArray& Array) const - { - if (mLength != Array.mLength) - return false; - - for (int i = 0; i < mLength; i++) - if (mData[i] != Array.mData[i]) - return false; - - return true; - } - - bool IsEmpty() const - { - return mLength == 0; - } - - int GetSize() const - { - return mLength; - } - - void SetSize(int NewSize) - { - if (NewSize > mAlloc) - AllocGrow(NewSize - mLength); - - mLength = NewSize; - } - - void SetGrow(int Grow) - { - if (Grow) - mGrow = Grow; - } - - void AllocGrow(int Grow) - { - if ((mLength + Grow) > mAlloc) - { - int NewSize = ((mLength + Grow + mGrow - 1) / mGrow) * mGrow; - T* NewData = new T[NewSize]; - - for (int i = 0; i < mLength; i++) - NewData[i] = mData[i]; - - delete[] mData; - mData = NewData; - mAlloc = NewSize; - } - } - - void Add(const T& NewItem) - { - AllocGrow(1); - mData[mLength++] = NewItem; - } - - T& Add() - { - AllocGrow(1); - return mData[mLength++]; - } - - void AddSorted(const T& Obj, lcArrayCompareFunc CompareFunc) - { - for (int i = 0; i < mLength; i++) - { - if (CompareFunc(Obj, mData[i]) < 0) - { - InsertAt(i, Obj); - return; - } - } - - Add(Obj); - } - - T& InsertAt(int Index) - { - if (Index >= mLength) - AllocGrow(Index - mLength + 1); - else - AllocGrow(1); - - mLength++; - for (int i = mLength - 1; i > Index; i--) - mData[i] = mData[i - 1]; - - return mData[Index]; - } - - void InsertAt(int Index, const T& NewItem) - { - if (Index >= mLength) - AllocGrow(Index - mLength + 1); - else - AllocGrow(1); - - mLength++; - for (int i = mLength - 1; i > Index; i--) - mData[i] = mData[i - 1]; - - mData[Index] = NewItem; - } - - void RemoveIndex(int Index) - { - mLength--; - - for (int i = Index; i < mLength; i++) - mData[i] = mData[i + 1]; - } - - void Remove(const T& Item) - { - for (int i = 0; i < mLength; i++) - { - if (mData[i] == Item) - { - RemoveIndex(i); - return; - } - } - } - - void RemoveAll() - { - mLength = 0; - } - - void DeleteAll() - { - for (int i = 0; i < mLength; i++) - delete mData[i]; - - mLength = 0; - } - - int FindIndex(const T& Item) const - { - for (int i = 0; i < mLength; i++) - if (mData[i] == Item) - return i; - - return -1; - } - - void Sort(lcArrayCompareFunc CompareFunc) - { - if (mLength <= 1) - return; - - int i = 1; - bool Flipped; - - do - { - Flipped = false; - - for (int j = mLength - 1; j >= i; --j) - { - T& a = mData[j]; - T& b = mData[j - 1]; - - if (CompareFunc(b, a) > 0) - { - T Tmp = b; - mData[j - 1] = a; - mData[j] = Tmp; - Flipped = true; - } - } - } while ((++i < mLength) && Flipped); - } - -protected: - T* mData; - int mLength; - int mAlloc; - int mGrow; -}; - -#endif // _LC_ARRAY_H_ +#ifndef _LC_ARRAY_H_ +#define _LC_ARRAY_H_ + +template +class lcArray +{ +public: + typedef int (*lcArrayCompareFunc)(const T& a, const T& b); + + lcArray(int Size = 0, int Grow = 16) + { + mData = NULL; + mLength = 0; + mAlloc = 0; + mGrow = Grow; + + if (Size != 0) + AllocGrow(Size); + } + + lcArray(const lcArray& Array) + { + mData = NULL; + *this = Array; + } + + ~lcArray() + { + delete[] mData; + } + + lcArray& operator=(const lcArray& Array) + { + mLength = Array.mLength; + mAlloc = Array.mAlloc; + mGrow = Array.mGrow; + + delete[] mData; + mData = new T[mAlloc]; + + for (int i = 0; i < mLength; i++) + mData[i] = Array.mData[i]; + + return *this; + } + + lcArray& operator+=(const lcArray& Array) + { + AllocGrow(Array.mLength); + + for (int i = 0; i < Array.mLength; i++) + mData[mLength + i] = Array.mData[i]; + + mLength += Array.mLength; + return *this; + } + + const T& operator[](int Index) const + { + return mData[Index]; + } + + T& operator[](int Index) + { + return mData[Index]; + } + + bool operator==(const lcArray& Array) const + { + if (mLength != Array.mLength) + return false; + + for (int i = 0; i < mLength; i++) + if (mData[i] != Array.mData[i]) + return false; + + return true; + } + + bool IsEmpty() const + { + return mLength == 0; + } + + int GetSize() const + { + return mLength; + } + + void SetSize(int NewSize) + { + if (NewSize > mAlloc) + AllocGrow(NewSize - mLength); + + mLength = NewSize; + } + + void SetGrow(int Grow) + { + if (Grow) + mGrow = Grow; + } + + void AllocGrow(int Grow) + { + if ((mLength + Grow) > mAlloc) + { + int NewSize = ((mLength + Grow + mGrow - 1) / mGrow) * mGrow; + T* NewData = new T[NewSize]; + + for (int i = 0; i < mLength; i++) + NewData[i] = mData[i]; + + delete[] mData; + mData = NewData; + mAlloc = NewSize; + } + } + + void Add(const T& NewItem) + { + AllocGrow(1); + mData[mLength++] = NewItem; + } + + T& Add() + { + AllocGrow(1); + return mData[mLength++]; + } + + void AddSorted(const T& Obj, lcArrayCompareFunc CompareFunc) + { + for (int i = 0; i < mLength; i++) + { + if (CompareFunc(Obj, mData[i]) < 0) + { + InsertAt(i, Obj); + return; + } + } + + Add(Obj); + } + + T& InsertAt(int Index) + { + if (Index >= mLength) + AllocGrow(Index - mLength + 1); + else + AllocGrow(1); + + mLength++; + for (int i = mLength - 1; i > Index; i--) + mData[i] = mData[i - 1]; + + return mData[Index]; + } + + void InsertAt(int Index, const T& NewItem) + { + if (Index >= mLength) + AllocGrow(Index - mLength + 1); + else + AllocGrow(1); + + mLength++; + for (int i = mLength - 1; i > Index; i--) + mData[i] = mData[i - 1]; + + mData[Index] = NewItem; + } + + void RemoveIndex(int Index) + { + mLength--; + + for (int i = Index; i < mLength; i++) + mData[i] = mData[i + 1]; + } + + void Remove(const T& Item) + { + for (int i = 0; i < mLength; i++) + { + if (mData[i] == Item) + { + RemoveIndex(i); + return; + } + } + } + + void RemoveAll() + { + mLength = 0; + } + + void DeleteAll() + { + for (int i = 0; i < mLength; i++) + delete mData[i]; + + mLength = 0; + } + + int FindIndex(const T& Item) const + { + for (int i = 0; i < mLength; i++) + if (mData[i] == Item) + return i; + + return -1; + } + + void Sort(lcArrayCompareFunc CompareFunc) + { + if (mLength <= 1) + return; + + int i = 1; + bool Flipped; + + do + { + Flipped = false; + + for (int j = mLength - 1; j >= i; --j) + { + T& a = mData[j]; + T& b = mData[j - 1]; + + if (CompareFunc(b, a) > 0) + { + T Tmp = b; + mData[j - 1] = a; + mData[j] = Tmp; + Flipped = true; + } + } + } while ((++i < mLength) && Flipped); + } + +protected: + T* mData; + int mLength; + int mAlloc; + int mGrow; +}; + +#endif // _LC_ARRAY_H_ diff --git a/common/lc_context.cpp b/common/lc_context.cpp index d5a5ce15..894ca143 100644 --- a/common/lc_context.cpp +++ b/common/lc_context.cpp @@ -1,1135 +1,1135 @@ -#include "lc_global.h" -#include "lc_context.h" -#include "lc_glextensions.h" -#include "lc_mesh.h" -#include "lc_texture.h" -#include "lc_colors.h" -#include "lc_mainwindow.h" -#include "lc_library.h" - -lcProgram lcContext::mPrograms[LC_NUM_PROGRAMS]; - -static int lcOpaqueRenderMeshCompare(const void* Elem1, const void* Elem2) -{ - lcRenderMesh* Mesh1 = (lcRenderMesh*)Elem1; - lcRenderMesh* Mesh2 = (lcRenderMesh*)Elem2; - - if (Mesh1->Mesh < Mesh2->Mesh) - return -1; - - if (Mesh1->Mesh > Mesh2->Mesh) - return 1; - - return 0; -} - -static int lcTranslucentRenderMeshCompare(const void* Elem1, const void* Elem2) -{ - lcRenderMesh* Mesh1 = (lcRenderMesh*)Elem1; - lcRenderMesh* Mesh2 = (lcRenderMesh*)Elem2; - - if (Mesh1->Distance < Mesh2->Distance) - return 1; - - if (Mesh1->Distance > Mesh2->Distance) - return -1; - - return 0; -} - -lcScene::lcScene() - : mOpaqueMeshes(0, 1024), mTranslucentMeshes(0, 1024), mInterfaceObjects(0, 1024) -{ -} - -void lcScene::Begin(const lcMatrix44& ViewMatrix) -{ - mViewMatrix = ViewMatrix; - mOpaqueMeshes.RemoveAll(); - mTranslucentMeshes.RemoveAll(); - mInterfaceObjects.RemoveAll(); -} - -void lcScene::End() -{ - qsort(&mOpaqueMeshes[0], mOpaqueMeshes.GetSize(), sizeof(mOpaqueMeshes[0]), lcOpaqueRenderMeshCompare); - qsort(&mTranslucentMeshes[0], mTranslucentMeshes.GetSize(), sizeof(mTranslucentMeshes[0]), lcTranslucentRenderMeshCompare); -} - -lcContext::lcContext() -{ - mVertexBufferObject = 0; - mIndexBufferObject = 0; - mVertexBufferPointer = NULL; - mIndexBufferPointer = NULL; - mVertexBufferOffset = (char*)~0; - - mTexCoordEnabled = false; - mColorEnabled = false; - - mTexture = NULL; - mLineWidth = 1.0f; - mMatrixMode = GL_MODELVIEW; - - mFramebufferObject = 0; - mFramebufferTexture = 0; - mDepthRenderbufferObject = 0; - - mViewportX = 0; - mViewportY = 0; - mViewportWidth = 1; - mViewportHeight = 1; - - mColor = lcVector4(0.0f, 0.0f, 0.0f, 0.0f); - mWorldMatrix = lcMatrix44Identity(); - mViewMatrix = lcMatrix44Identity(); - mProjectionMatrix = lcMatrix44Identity(); - mViewProjectionMatrix = lcMatrix44Identity(); - mColorDirty = false; - mWorldMatrixDirty = false; - mViewMatrixDirty = false; - mProjectionMatrixDirty = false; - mViewProjectionMatrixDirty = false; - - mProgramType = LC_NUM_PROGRAMS; -} - -lcContext::~lcContext() -{ -} - -void lcContext::CreateShaderPrograms() -{ - const char* VertexShaders[LC_NUM_PROGRAMS] = - { - // LC_PROGRAM_SIMPLE - "#version 110\n" - "attribute vec3 VertexPosition;\n" - "uniform mat4 WorldViewProjectionMatrix;\n" - "void main()\n" - "{\n" - " gl_Position = WorldViewProjectionMatrix * vec4(VertexPosition, 1.0);\n" - "}\n", - // LC_PROGRAM_TEXTURE - "#version 110\n" - "attribute vec3 VertexPosition;\n" - "attribute vec2 VertexTexCoord;\n" - "varying vec2 PixelTexCoord;\n" - "uniform mat4 WorldViewProjectionMatrix;\n" - "void main()\n" - "{\n" - " gl_Position = WorldViewProjectionMatrix * vec4(VertexPosition, 1.0);\n" - " PixelTexCoord = VertexTexCoord;\n" - "}\n", - // LC_PROGRAM_VERTEX_COLOR - "#version 110\n" - "attribute vec3 VertexPosition;\n" - "attribute vec4 VertexColor;\n" - "varying vec4 PixelColor;\n" - "uniform mat4 WorldViewProjectionMatrix;\n" - "void main()\n" - "{\n" - " gl_Position = WorldViewProjectionMatrix * vec4(VertexPosition, 1.0);\n" - " PixelColor = VertexColor;\n" - "}\n" - }; - - const char* FragmentShaders[LC_NUM_PROGRAMS] = - { - // LC_PROGRAM_SIMPLE - "#version 110\n" - "uniform vec4 Color;\n" - "void main()\n" - "{\n" - " gl_FragColor = Color;\n" - "}\n", - // LC_PROGRAM_TEXTURE - "#version 110\n" - "varying vec2 PixelTexCoord;\n" - "uniform vec4 Color;\n" - "uniform sampler2D Texture;\n" - "void main()\n" - "{\n" - " gl_FragColor = texture2D(Texture, PixelTexCoord) * Color;\n" - "}\n", - // LC_PROGRAM_VERTEX_COLOR - "#version 110\n" - "varying vec4 PixelColor;\n" - "void main()\n" - "{\n" - " gl_FragColor = PixelColor;\n" - "}\n" - }; - - for (int ProgramIdx = 0; ProgramIdx < LC_NUM_PROGRAMS; ProgramIdx++) - { - GLuint VertexShader = glCreateShader(GL_VERTEX_SHADER); - glShaderSource(VertexShader, 1, &VertexShaders[ProgramIdx], NULL); - glCompileShader(VertexShader); - -#ifndef QT_NO_DEBUG - GLint VertexShaderCompiled = 0; - glGetShaderiv(VertexShader, GL_COMPILE_STATUS, &VertexShaderCompiled); - - if (VertexShaderCompiled == GL_FALSE) - { - GLint Length = 0; - glGetShaderiv(VertexShader, GL_INFO_LOG_LENGTH, &Length); - - QByteArray InfoLog; - InfoLog.resize(Length); - glGetShaderInfoLog(VertexShader, Length, &Length, InfoLog.data()); - - qDebug() << InfoLog; - } -#endif - - GLuint FragmentShader = glCreateShader(GL_FRAGMENT_SHADER); - glShaderSource(FragmentShader, 1, &FragmentShaders[ProgramIdx], NULL); - glCompileShader(FragmentShader); - -#ifndef QT_NO_DEBUG - GLint FragmentShaderCompiled = 0; - glGetShaderiv(FragmentShader, GL_COMPILE_STATUS, &FragmentShaderCompiled); - - if (FragmentShaderCompiled == GL_FALSE) - { - GLint Length = 0; - glGetShaderiv(FragmentShader, GL_INFO_LOG_LENGTH, &Length); - - QByteArray InfoLog; - InfoLog.resize(Length); - glGetShaderInfoLog(FragmentShader, Length, &Length, InfoLog.data()); - - qDebug() << InfoLog; - } -#endif - - GLuint Program = glCreateProgram(); - - glAttachShader(Program, VertexShader); - glAttachShader(Program, FragmentShader); - - glBindAttribLocation(Program, LC_ATTRIB_POSITION, "VertexPosition"); - glBindAttribLocation(Program, LC_ATTRIB_TEXCOORD, "VertexTexCoord"); - glBindAttribLocation(Program, LC_ATTRIB_COLOR, "VertexColor"); - - glLinkProgram(Program); - - glDetachShader(Program, VertexShader); - glDetachShader(Program, FragmentShader); - glDeleteShader(VertexShader); - glDeleteShader(FragmentShader); - - GLint IsLinked = 0; - glGetProgramiv(Program, GL_LINK_STATUS, &IsLinked); - if (IsLinked == GL_FALSE) - { - GLint Length = 0; - glGetProgramiv(Program, GL_INFO_LOG_LENGTH, &Length); - - QByteArray InfoLog; - InfoLog.resize(Length); - glGetProgramInfoLog(Program, Length, &Length, InfoLog.data()); - - glDeleteProgram(Program); - Program = 0; - } - - mPrograms[ProgramIdx].Object = Program; - mPrograms[ProgramIdx].MatrixLocation = glGetUniformLocation(Program, "WorldViewProjectionMatrix"); - mPrograms[ProgramIdx].ColorLocation = glGetUniformLocation(Program, "Color"); - } -} - -void lcContext::CreateResources() -{ - if (!gSupportsShaderObjects) - return; - - CreateShaderPrograms(); -} - -void lcContext::DestroyResources() -{ - if (!gSupportsShaderObjects) - return; - - for (int ProgramIdx = 0; ProgramIdx < LC_NUM_PROGRAMS; ProgramIdx++) - glDeleteProgram(mPrograms[ProgramIdx].Object); -} - -void lcContext::SetDefaultState() -{ - glEnable(GL_DEPTH_TEST); - glDepthFunc(GL_LEQUAL); - - glEnable(GL_POLYGON_OFFSET_FILL); - glPolygonOffset(0.5f, 0.1f); - - if (gSupportsVertexBufferObject) - { - glBindBuffer(GL_ARRAY_BUFFER_ARB, 0); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER_ARB, 0); - } - - if (gSupportsShaderObjects) - { - glEnableVertexAttribArray(LC_ATTRIB_POSITION); - glDisableVertexAttribArray(LC_ATTRIB_TEXCOORD); - glDisableVertexAttribArray(LC_ATTRIB_COLOR); - } - else - { - glEnableClientState(GL_VERTEX_ARRAY); - glDisableClientState(GL_TEXTURE_COORD_ARRAY); - glDisableClientState(GL_COLOR_ARRAY); - - glVertexPointer(3, GL_FLOAT, 0, NULL); - glTexCoordPointer(2, GL_FLOAT, 0, NULL); - glColorPointer(4, GL_FLOAT, 0, NULL); - } - - mTexCoordEnabled = false; - mColorEnabled = false; - - mVertexBufferObject = 0; - mIndexBufferObject = 0; - mVertexBufferPointer = NULL; - mIndexBufferPointer = NULL; - mVertexBufferOffset = (char*)~0; - - glDisable(GL_TEXTURE_2D); - mTexture = NULL; - - glLineWidth(1.0f); - mLineWidth = 1.0f; - - if (gSupportsShaderObjects) - { - glUseProgram(0); - mProgramType = LC_NUM_PROGRAMS; - } - else - { - glMatrixMode(GL_MODELVIEW); - mMatrixMode = GL_MODELVIEW; - } -} - -void lcContext::SetProgram(lcProgramType ProgramType) -{ - if (!gSupportsShaderObjects || mProgramType == ProgramType) - return; - - glUseProgram(mPrograms[ProgramType].Object); - mProgramType = ProgramType; - mColorDirty = true; - mWorldMatrixDirty = true; -} - -void lcContext::SetViewport(int x, int y, int Width, int Height) -{ - if (mViewportX == x && mViewportY == y && mViewportWidth == Width && mViewportHeight == Height) - return; - - glViewport(x, y, Width, Height); - - mViewportX = x; - mViewportY = y; - mViewportWidth = Width; - mViewportHeight = Height; -} - -void lcContext::SetLineWidth(float LineWidth) -{ - if (LineWidth == mLineWidth) - return; - - glLineWidth(LineWidth); - mLineWidth = LineWidth; -} - -void lcContext::SetColor(float Red, float Green, float Blue, float Alpha) -{ - SetColor(lcVector4(Red, Green, Blue, Alpha)); -} - -void lcContext::SetColorIndex(int ColorIndex) -{ - SetColor(gColorList[ColorIndex].Value); -} - -void lcContext::SetColorIndexTinted(int ColorIndex, lcInterfaceColor InterfaceColor) -{ - SetColor((gColorList[ColorIndex].Value + gInterfaceColors[InterfaceColor]) * 0.5f); -} - -void lcContext::SetEdgeColorIndex(int ColorIndex) -{ - SetColor(gColorList[ColorIndex].Edge); -} - -void lcContext::SetInterfaceColor(lcInterfaceColor InterfaceColor) -{ - SetColor(gInterfaceColors[InterfaceColor]); -} - -bool lcContext::BeginRenderToTexture(int Width, int Height) -{ - if (gSupportsFramebufferObjectARB) - { - glGenFramebuffers(1, &mFramebufferObject); - glGenTextures(1, &mFramebufferTexture); - glGenRenderbuffers(1, &mDepthRenderbufferObject); - - glBindFramebuffer(GL_DRAW_FRAMEBUFFER, mFramebufferObject); - - glBindTexture(GL_TEXTURE_2D, mFramebufferTexture); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, Width, Height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); - glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mFramebufferTexture, 0); - - glBindRenderbuffer(GL_RENDERBUFFER, mDepthRenderbufferObject); - glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, Width, Height); - glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, mDepthRenderbufferObject); - - glBindTexture(GL_TEXTURE_2D, 0); - glBindFramebuffer(GL_FRAMEBUFFER, mFramebufferObject); - - if (glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) - { - EndRenderToTexture(); - return false; - } - - return true; - } - - if (gSupportsFramebufferObjectEXT) - { - glGenFramebuffersEXT(1, &mFramebufferObject); - glGenTextures(1, &mFramebufferTexture); - - glBindTexture(GL_TEXTURE_2D, mFramebufferTexture); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, Width, Height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); - - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, mFramebufferObject); - glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, mFramebufferTexture, 0); - - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, mFramebufferObject); - - glGenRenderbuffersEXT(1, &mDepthRenderbufferObject); - glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, mDepthRenderbufferObject); - glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT24, Width, Height); - - glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, mDepthRenderbufferObject); - - glBindTexture(GL_TEXTURE_2D, 0); - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, mFramebufferObject); - - if (glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT) != GL_FRAMEBUFFER_COMPLETE_EXT) - { - EndRenderToTexture(); - return false; - } - - return true; - } - - return false; -} - -void lcContext::EndRenderToTexture() -{ - if (gSupportsFramebufferObjectARB) - { - glDeleteFramebuffers(1, &mFramebufferObject); - mFramebufferObject = 0; - glDeleteTextures(1, &mFramebufferTexture); - mFramebufferTexture = 0; - glDeleteRenderbuffers(1, &mDepthRenderbufferObject); - mDepthRenderbufferObject = 0; - - return; - } - - if (gSupportsFramebufferObjectEXT) - { - glDeleteFramebuffersEXT(1, &mFramebufferObject); - mFramebufferObject = 0; - glDeleteTextures(1, &mFramebufferTexture); - mFramebufferTexture = 0; - glDeleteRenderbuffersEXT(1, &mDepthRenderbufferObject); - mDepthRenderbufferObject = 0; - } -} - -bool lcContext::SaveRenderToTextureImage(const QString& FileName, int Width, int Height) -{ - lcuint8* Buffer = (lcuint8*)malloc(Width * Height * 4); - - glFinish(); - glReadPixels(0, 0, Width, Height, GL_RGBA, GL_UNSIGNED_BYTE, Buffer); - - for (int y = 0; y < (Height + 1) / 2; y++) - { - lcuint8* Top = Buffer + ((Height - y - 1) * Width * 4); - lcuint8* Bottom = Buffer + y * Width * 4; - - for (int x = 0; x < Width; x++) - { - lcuint8 Red = Top[0]; - lcuint8 Green = Top[1]; - lcuint8 Blue = Top[2]; - lcuint8 Alpha = Top[3]; - - Top[0] = Bottom[2]; - Top[1] = Bottom[1]; - Top[2] = Bottom[0]; - Top[3] = Bottom[3]; - - Bottom[0] = Blue; - Bottom[1] = Green; - Bottom[2] = Red; - Bottom[3] = Alpha; - - Top += 4; - Bottom +=4; - } - } - - QImageWriter Writer(FileName); - bool Result = Writer.write(QImage(Buffer, Width, Height, QImage::Format_ARGB32)); - - if (!Result) - QMessageBox::information(gMainWindow, tr("Error"), tr("Error writing to file '%1':\n%2").arg(FileName, Writer.errorString())); - - free(Buffer); - - return Result; -} - -lcVertexBuffer lcContext::CreateVertexBuffer(int Size, const void* Data) -{ - lcVertexBuffer VertexBuffer; - - if (gSupportsVertexBufferObject) - { - glGenBuffers(1, &VertexBuffer.Object); - glBindBuffer(GL_ARRAY_BUFFER_ARB, VertexBuffer.Object); - glBufferData(GL_ARRAY_BUFFER_ARB, Size, Data, GL_STATIC_DRAW_ARB); - - glBindBuffer(GL_ARRAY_BUFFER_ARB, 0); // context remove - mVertexBufferObject = 0; - } - else - { - VertexBuffer.Pointer = malloc(Size); - memcpy(VertexBuffer.Pointer, Data, Size); - } - - return VertexBuffer; -} - -void lcContext::DestroyVertexBuffer(lcVertexBuffer& VertexBuffer) -{ - if (!VertexBuffer.IsValid()) - return; - - if (gSupportsVertexBufferObject) - { - if (mVertexBufferObject == VertexBuffer.Object) - { - glBindBuffer(GL_ARRAY_BUFFER_ARB, 0); - mVertexBufferObject = 0; - } - - glDeleteBuffers(1, &VertexBuffer.Object); - } - else - { - free(VertexBuffer.Pointer); - } - - VertexBuffer.Pointer = NULL; -} - -lcIndexBuffer lcContext::CreateIndexBuffer(int Size, const void* Data) -{ - lcIndexBuffer IndexBuffer; - - if (gSupportsVertexBufferObject) - { - glGenBuffers(1, &IndexBuffer.Object); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER_ARB, IndexBuffer.Object); - glBufferData(GL_ELEMENT_ARRAY_BUFFER_ARB, Size, Data, GL_STATIC_DRAW_ARB); - - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER_ARB, 0); // context remove - mIndexBufferObject = 0; - } - else - { - IndexBuffer.Pointer = malloc(Size); - memcpy(IndexBuffer.Pointer, Data, Size); - } - - return IndexBuffer; -} - -void lcContext::DestroyIndexBuffer(lcIndexBuffer& IndexBuffer) -{ - if (!IndexBuffer.IsValid()) - return; - - if (gSupportsVertexBufferObject) - { - if (mIndexBufferObject == IndexBuffer.Object) - { - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER_ARB, 0); - mIndexBufferObject = 0; - } - - glDeleteBuffers(1, &IndexBuffer.Object); - } - else - { - free(IndexBuffer.Pointer); - } - - IndexBuffer.Pointer = NULL; -} - -void lcContext::ClearVertexBuffer() -{ - mVertexBufferPointer = NULL; - mVertexBufferOffset = (char*)~0; - - if (mVertexBufferObject) - { - glBindBuffer(GL_ARRAY_BUFFER_ARB, 0); - mVertexBufferObject = 0; - } - - if (mTexCoordEnabled) - glDisableClientState(GL_TEXTURE_COORD_ARRAY); - - if (mColorEnabled) - glDisableClientState(GL_COLOR_ARRAY); -} - -void lcContext::SetVertexBuffer(lcVertexBuffer VertexBuffer) -{ - if (gSupportsVertexBufferObject) - { - GLuint VertexBufferObject = VertexBuffer.Object; - mVertexBufferPointer = NULL; - - if (VertexBufferObject != mVertexBufferObject) - { - glBindBuffer(GL_ARRAY_BUFFER_ARB, VertexBufferObject); - mVertexBufferObject = VertexBufferObject; - mVertexBufferOffset = (char*)~0; - } - } - else - { - mVertexBufferPointer = (char*)VertexBuffer.Pointer; - mVertexBufferOffset = (char*)~0; - } -} - -void lcContext::SetVertexBufferPointer(const void* VertexBuffer) -{ - if (gSupportsVertexBufferObject && mVertexBufferObject) - { - glBindBuffer(GL_ARRAY_BUFFER_ARB, 0); - mVertexBufferObject = 0; - } - - mVertexBufferPointer = (char*)VertexBuffer; - mVertexBufferOffset = (char*)~0; -} - -void lcContext::SetVertexFormat(int BufferOffset, int PositionSize, int TexCoordSize, int ColorSize) -{ - int VertexSize = (PositionSize + TexCoordSize + ColorSize) * sizeof(float); - char* VertexBufferPointer = mVertexBufferPointer + BufferOffset; - - if (mVertexBufferOffset != VertexBufferPointer) - { - if (gSupportsShaderObjects) - glVertexAttribPointer(LC_ATTRIB_POSITION, PositionSize, GL_FLOAT, false, VertexSize, VertexBufferPointer); - else - glVertexPointer(PositionSize, GL_FLOAT, VertexSize, VertexBufferPointer); - - mVertexBufferOffset = VertexBufferPointer; - } - - if (TexCoordSize) - { - if (gSupportsShaderObjects) - { - glVertexAttribPointer(LC_ATTRIB_TEXCOORD, TexCoordSize, GL_FLOAT, false, VertexSize, VertexBufferPointer + PositionSize * sizeof(float)); - - if (!mTexCoordEnabled) - { - glEnableVertexAttribArray(LC_ATTRIB_TEXCOORD); - mTexCoordEnabled = true; - } - } - else - { - glTexCoordPointer(TexCoordSize, GL_FLOAT, VertexSize, VertexBufferPointer + PositionSize * sizeof(float)); - - if (!mTexCoordEnabled) - { - glEnableClientState(GL_TEXTURE_COORD_ARRAY); - mTexCoordEnabled = true; - } - } - } - else if (mTexCoordEnabled) - { - if (gSupportsShaderObjects) - glDisableVertexAttribArray(LC_ATTRIB_TEXCOORD); - else - glDisableClientState(GL_TEXTURE_COORD_ARRAY); - mTexCoordEnabled = false; - } - - if (ColorSize) - { - if (gSupportsShaderObjects) - { - glVertexAttribPointer(LC_ATTRIB_COLOR, ColorSize, GL_FLOAT, false, VertexSize, VertexBufferPointer + (PositionSize + TexCoordSize) * sizeof(float)); - - if (!mColorEnabled) - { - glEnableVertexAttribArray(LC_ATTRIB_COLOR); - mColorEnabled = true; - } - } - else - { - glColorPointer(ColorSize, GL_FLOAT, VertexSize, VertexBufferPointer + (PositionSize + TexCoordSize) * sizeof(float)); - - if (!mColorEnabled) - { - glEnableClientState(GL_COLOR_ARRAY); - mColorEnabled = true; - } - } - } - else if (mColorEnabled) - { - if (gSupportsShaderObjects) - glDisableVertexAttribArray(LC_ATTRIB_COLOR); - else - glDisableClientState(GL_COLOR_ARRAY); - mColorEnabled = false; - } -} - -void lcContext::ClearIndexBuffer() -{ - if (mIndexBufferObject) - { - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER_ARB, 0); - mIndexBufferObject = 0; - } -} - -void lcContext::SetIndexBuffer(lcIndexBuffer IndexBuffer) -{ - if (gSupportsVertexBufferObject) - { - GLuint IndexBufferObject = IndexBuffer.Object; - mIndexBufferPointer = NULL; - - if (IndexBufferObject != mIndexBufferObject) - { - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER_ARB, IndexBufferObject); - mIndexBufferObject = IndexBufferObject; - } - } - else - { - mIndexBufferPointer = (char*)IndexBuffer.Pointer; - } -} - -void lcContext::SetIndexBufferPointer(const void* IndexBuffer) -{ - if (mIndexBufferObject) - { - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER_ARB, 0); - mIndexBufferObject = 0; - } - - mIndexBufferPointer = (char*)IndexBuffer; -} - -void lcContext::BindMesh(lcMesh* Mesh) -{ - lcPiecesLibrary* Library = lcGetPiecesLibrary(); - - if (Mesh->mVertexCacheOffset != -1) - { - GLuint VertexBufferObject = Library->mVertexBuffer.Object; - GLuint IndexBufferObject = Library->mIndexBuffer.Object; - - if (VertexBufferObject != mVertexBufferObject) - { - glBindBuffer(GL_ARRAY_BUFFER_ARB, VertexBufferObject); - mVertexBufferObject = VertexBufferObject; - mVertexBufferPointer = NULL; - mVertexBufferOffset = (char*)~0; - } - - if (IndexBufferObject != mIndexBufferObject) - { - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER_ARB, IndexBufferObject); - mIndexBufferObject = IndexBufferObject; - mIndexBufferPointer = NULL; - } - } - else - { - if (mVertexBufferObject) - { - glBindBuffer(GL_ARRAY_BUFFER_ARB, 0); - mVertexBufferObject = 0; - } - - if (mIndexBufferObject) - { - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER_ARB, 0); - mIndexBufferObject = 0; - } - - mVertexBufferPointer = (char*)Mesh->mVertexData; - mIndexBufferPointer = (char*)Mesh->mIndexData; - mVertexBufferOffset = (char*)~0; - } -} - -void lcContext::UnbindMesh() -{ - if (mTexture) - { - glDisableClientState(GL_TEXTURE_COORD_ARRAY); - glDisable(GL_TEXTURE_2D); - mTexture = NULL; - } - - if (gSupportsVertexBufferObject) - { - glBindBuffer(GL_ARRAY_BUFFER_ARB, 0); - mVertexBufferObject = 0; - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER_ARB, 0); - mIndexBufferObject = 0; - } - - mVertexBufferPointer = NULL; - mIndexBufferPointer = NULL; - - if (gSupportsShaderObjects) - { - glDisableVertexAttribArray(LC_ATTRIB_TEXCOORD); - glDisableVertexAttribArray(LC_ATTRIB_COLOR); - } - else - { - glVertexPointer(3, GL_FLOAT, 0, NULL); - glTexCoordPointer(2, GL_FLOAT, 0, NULL); - } - mTexCoordEnabled = false; - mColorEnabled = false; -} - -void lcContext::FlushState() -{ - if (gSupportsShaderObjects) - { - if (mWorldMatrixDirty || mViewMatrixDirty || mProjectionMatrixDirty) - { - if (mViewProjectionMatrixDirty) - { - mViewProjectionMatrix = lcMul(mViewMatrix, mProjectionMatrix); - mViewProjectionMatrixDirty = false; - } - - glUniformMatrix4fv(mPrograms[mProgramType].MatrixLocation, 1, false, lcMul(mWorldMatrix, mViewProjectionMatrix)); - mWorldMatrixDirty = false; - mViewMatrixDirty = false; - mProjectionMatrixDirty = false; - } - - if (mColorDirty && mPrograms[mProgramType].ColorLocation != -1) - { - glUniform4fv(mPrograms[mProgramType].ColorLocation, 1, mColor); - mColorDirty = false; - } - } - else - { - glColor4fv(mColor); - - if (mWorldMatrixDirty || mViewMatrixDirty) - { - if (mMatrixMode != GL_MODELVIEW) - { - glMatrixMode(GL_MODELVIEW); - mMatrixMode = GL_MODELVIEW; - } - - glLoadMatrixf(lcMul(mWorldMatrix, mViewMatrix)); - mWorldMatrixDirty = false; - mViewMatrixDirty = false; - } - - if (mProjectionMatrixDirty) - { - if (mMatrixMode != GL_PROJECTION) - { - glMatrixMode(GL_PROJECTION); - mMatrixMode = GL_PROJECTION; - } - - glLoadMatrixf(mProjectionMatrix); - mProjectionMatrixDirty = false; - } - } -} - -void lcContext::DrawPrimitives(GLenum Mode, GLint First, GLsizei Count) -{ - FlushState(); - glDrawArrays(Mode, First, Count); -} - -void lcContext::DrawIndexedPrimitives(GLenum Mode, GLsizei Count, GLenum Type, int Offset) -{ - FlushState(); - glDrawElements(Mode, Count, Type, mIndexBufferPointer + Offset); -} - -void lcContext::DrawMeshSection(lcMesh* Mesh, lcMeshSection* Section) -{ - lcTexture* Texture = Section->Texture; - int VertexBufferOffset = Mesh->mVertexCacheOffset != -1 ? Mesh->mVertexCacheOffset : 0; - int IndexBufferOffset = Mesh->mIndexCacheOffset != -1 ? Mesh->mIndexCacheOffset : 0; - - if (!Texture) - { - SetProgram(LC_PROGRAM_SIMPLE); - SetVertexFormat(VertexBufferOffset, 3, 0, 0); - - if (mTexture) - { - glDisable(GL_TEXTURE_2D); - mTexture = NULL; - } - } - else - { - VertexBufferOffset += Mesh->mNumVertices * sizeof(lcVertex); - SetProgram(LC_PROGRAM_TEXTURE); - SetVertexFormat(VertexBufferOffset, 3, 2, 0); - - if (Texture != mTexture) - { - glBindTexture(GL_TEXTURE_2D, Texture->mTexture); - - if (!mTexture) - { - glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL); - glEnable(GL_TEXTURE_2D); - } - - mTexture = Texture; - } - } - - bool DrawConditional = false; - - if (Section->PrimitiveType != LC_MESH_CONDITIONAL_LINES) - { - GLenum PrimitiveType = (Section->PrimitiveType == LC_MESH_TRIANGLES || Section->PrimitiveType == LC_MESH_TEXTURED_TRIANGLES) ? GL_TRIANGLES : GL_LINES; - DrawIndexedPrimitives(PrimitiveType, Section->NumIndices, Mesh->mIndexType, IndexBufferOffset + Section->IndexOffset); - } - else if (DrawConditional) - { - FlushState(); - lcMatrix44 WorldViewProjectionMatrix = lcMul(mWorldMatrix, mViewProjectionMatrix); - float* VertexBuffer = (float*)Mesh->mVertexData; - - if (Mesh->mIndexType == GL_UNSIGNED_SHORT) - { - lcuint16* Indices = (lcuint16*)((char*)Mesh->mIndexData + Section->IndexOffset); - - for (int i = 0; i < Section->NumIndices; i += 4) - { - lcVector3 p1 = lcMul31(lcVector3(VertexBuffer[Indices[i] * 3], VertexBuffer[Indices[i] * 3 + 1], VertexBuffer[Indices[i] * 3 + 2]), WorldViewProjectionMatrix); - lcVector3 p2 = lcMul31(lcVector3(VertexBuffer[Indices[i + 1] * 3], VertexBuffer[Indices[i + 1] * 3 + 1], VertexBuffer[Indices[i + 1] * 3 + 2]), WorldViewProjectionMatrix); - lcVector3 p3 = lcMul31(lcVector3(VertexBuffer[Indices[i + 2] * 3], VertexBuffer[Indices[i + 2] * 3 + 1], VertexBuffer[Indices[i + 2] * 3 + 2]), WorldViewProjectionMatrix); - lcVector3 p4 = lcMul31(lcVector3(VertexBuffer[Indices[i + 3] * 3], VertexBuffer[Indices[i + 3] * 3 + 1], VertexBuffer[Indices[i + 3] * 3 + 2]), WorldViewProjectionMatrix); - - if (((p1.y - p2.y) * (p3.x - p1.x) + (p2.x - p1.x) * (p3.y - p1.y)) * ((p1.y - p2.y) * (p4.x - p1.x) + (p2.x - p1.x) * (p4.y - p1.y)) >= 0) - DrawIndexedPrimitives(GL_LINES, 2, Mesh->mIndexType, IndexBufferOffset + Section->IndexOffset + i * sizeof(lcuint16)); - } - } - else - { - lcuint32* Indices = (lcuint32*)((char*)Mesh->mIndexData + Section->IndexOffset); - - for (int i = 0; i < Section->NumIndices; i += 4) - { - lcVector3 p1 = lcMul31(lcVector3(VertexBuffer[Indices[i] * 3], VertexBuffer[Indices[i] * 3 + 1], VertexBuffer[Indices[i] * 3 + 2]), WorldViewProjectionMatrix); - lcVector3 p2 = lcMul31(lcVector3(VertexBuffer[Indices[i + 1] * 3], VertexBuffer[Indices[i + 1] * 3 + 1], VertexBuffer[Indices[i + 1] * 3 + 2]), WorldViewProjectionMatrix); - lcVector3 p3 = lcMul31(lcVector3(VertexBuffer[Indices[i + 2] * 3], VertexBuffer[Indices[i + 2] * 3 + 1], VertexBuffer[Indices[i + 2] * 3 + 2]), WorldViewProjectionMatrix); - lcVector3 p4 = lcMul31(lcVector3(VertexBuffer[Indices[i + 3] * 3], VertexBuffer[Indices[i + 3] * 3 + 1], VertexBuffer[Indices[i + 3] * 3 + 2]), WorldViewProjectionMatrix); - - if (((p1.y - p2.y) * (p3.x - p1.x) + (p2.x - p1.x) * (p3.y - p1.y)) * ((p1.y - p2.y) * (p4.x - p1.x) + (p2.x - p1.x) * (p4.y - p1.y)) >= 0) - DrawIndexedPrimitives(GL_LINES, 2, Mesh->mIndexType, IndexBufferOffset + Section->IndexOffset + i * sizeof(lcuint32)); - } - } - } -} - -void lcContext::DrawOpaqueMeshes(const lcArray& OpaqueMeshes) -{ - bool DrawLines = lcGetPreferences().mDrawEdgeLines; - - lcGetPiecesLibrary()->UpdateBuffers(this); // TODO: find a better place for this update - - for (int MeshIdx = 0; MeshIdx < OpaqueMeshes.GetSize(); MeshIdx++) - { - const lcRenderMesh& RenderMesh = OpaqueMeshes[MeshIdx]; - lcMesh* Mesh = RenderMesh.Mesh; - int LodIndex = RenderMesh.LodIndex; - - BindMesh(Mesh); - SetWorldMatrix(RenderMesh.WorldMatrix); - - for (int SectionIdx = 0; SectionIdx < Mesh->mLods[LodIndex].NumSections; SectionIdx++) - { - lcMeshSection* Section = &Mesh->mLods[LodIndex].Sections[SectionIdx]; - int ColorIndex = Section->ColorIndex; - - if (Section->PrimitiveType == LC_MESH_TRIANGLES || Section->PrimitiveType == LC_MESH_TEXTURED_TRIANGLES) - { - if (ColorIndex == gDefaultColor) - ColorIndex = RenderMesh.ColorIndex; - - if (lcIsColorTranslucent(ColorIndex)) - continue; - - switch (RenderMesh.State) - { - case LC_RENDERMESH_NONE: - SetColorIndex(ColorIndex); - break; - - case LC_RENDERMESH_SELECTED: - SetColorIndexTinted(ColorIndex, LC_COLOR_SELECTED); - break; - - case LC_RENDERMESH_FOCUSED: - SetColorIndexTinted(ColorIndex, LC_COLOR_FOCUSED); - break; - } - } - else - { - switch (RenderMesh.State) - { - case LC_RENDERMESH_NONE: - if (DrawLines) - { - if (ColorIndex == gEdgeColor) - SetEdgeColorIndex(RenderMesh.ColorIndex); - else - SetColorIndex(ColorIndex); - } - else - continue; - break; - - case LC_RENDERMESH_SELECTED: - SetInterfaceColor(LC_COLOR_SELECTED); - break; - - case LC_RENDERMESH_FOCUSED: - SetInterfaceColor(LC_COLOR_FOCUSED); - break; - } - } - - DrawMeshSection(Mesh, Section); - } - } -} - -void lcContext::DrawTranslucentMeshes(const lcArray& TranslucentMeshes) -{ - if (TranslucentMeshes.IsEmpty()) - return; - - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glEnable(GL_BLEND); - glDepthMask(GL_FALSE); - - for (int MeshIdx = 0; MeshIdx < TranslucentMeshes.GetSize(); MeshIdx++) - { - const lcRenderMesh& RenderMesh = TranslucentMeshes[MeshIdx]; - lcMesh* Mesh = RenderMesh.Mesh; - int LodIndex = RenderMesh.LodIndex; - - BindMesh(Mesh); - SetWorldMatrix(RenderMesh.WorldMatrix); - - for (int SectionIdx = 0; SectionIdx < Mesh->mLods[LodIndex].NumSections; SectionIdx++) - { - lcMeshSection* Section = &Mesh->mLods[LodIndex].Sections[SectionIdx]; - int ColorIndex = Section->ColorIndex; - - if (Section->PrimitiveType != LC_MESH_TRIANGLES) - continue; - - if (ColorIndex == gDefaultColor) - ColorIndex = RenderMesh.ColorIndex; - - if (!lcIsColorTranslucent(ColorIndex)) - continue; - - switch (RenderMesh.State) - { - case LC_RENDERMESH_NONE: - SetColorIndex(ColorIndex); - break; - - case LC_RENDERMESH_SELECTED: - SetColorIndexTinted(ColorIndex, LC_COLOR_SELECTED); - break; - - case LC_RENDERMESH_FOCUSED: - SetColorIndexTinted(ColorIndex, LC_COLOR_FOCUSED); - break; - } - - DrawMeshSection(Mesh, Section); - } - } - - glDepthMask(GL_TRUE); - glDisable(GL_BLEND); -} - -void lcContext::DrawInterfaceObjects(const lcArray& InterfaceObjects) -{ - for (int ObjectIdx = 0; ObjectIdx < InterfaceObjects.GetSize(); ObjectIdx++) - InterfaceObjects[ObjectIdx]->DrawInterface(this); -} +#include "lc_global.h" +#include "lc_context.h" +#include "lc_glextensions.h" +#include "lc_mesh.h" +#include "lc_texture.h" +#include "lc_colors.h" +#include "lc_mainwindow.h" +#include "lc_library.h" + +lcProgram lcContext::mPrograms[LC_NUM_PROGRAMS]; + +static int lcOpaqueRenderMeshCompare(const void* Elem1, const void* Elem2) +{ + lcRenderMesh* Mesh1 = (lcRenderMesh*)Elem1; + lcRenderMesh* Mesh2 = (lcRenderMesh*)Elem2; + + if (Mesh1->Mesh < Mesh2->Mesh) + return -1; + + if (Mesh1->Mesh > Mesh2->Mesh) + return 1; + + return 0; +} + +static int lcTranslucentRenderMeshCompare(const void* Elem1, const void* Elem2) +{ + lcRenderMesh* Mesh1 = (lcRenderMesh*)Elem1; + lcRenderMesh* Mesh2 = (lcRenderMesh*)Elem2; + + if (Mesh1->Distance < Mesh2->Distance) + return 1; + + if (Mesh1->Distance > Mesh2->Distance) + return -1; + + return 0; +} + +lcScene::lcScene() + : mOpaqueMeshes(0, 1024), mTranslucentMeshes(0, 1024), mInterfaceObjects(0, 1024) +{ +} + +void lcScene::Begin(const lcMatrix44& ViewMatrix) +{ + mViewMatrix = ViewMatrix; + mOpaqueMeshes.RemoveAll(); + mTranslucentMeshes.RemoveAll(); + mInterfaceObjects.RemoveAll(); +} + +void lcScene::End() +{ + qsort(&mOpaqueMeshes[0], mOpaqueMeshes.GetSize(), sizeof(mOpaqueMeshes[0]), lcOpaqueRenderMeshCompare); + qsort(&mTranslucentMeshes[0], mTranslucentMeshes.GetSize(), sizeof(mTranslucentMeshes[0]), lcTranslucentRenderMeshCompare); +} + +lcContext::lcContext() +{ + mVertexBufferObject = 0; + mIndexBufferObject = 0; + mVertexBufferPointer = NULL; + mIndexBufferPointer = NULL; + mVertexBufferOffset = (char*)~0; + + mTexCoordEnabled = false; + mColorEnabled = false; + + mTexture = NULL; + mLineWidth = 1.0f; + mMatrixMode = GL_MODELVIEW; + + mFramebufferObject = 0; + mFramebufferTexture = 0; + mDepthRenderbufferObject = 0; + + mViewportX = 0; + mViewportY = 0; + mViewportWidth = 1; + mViewportHeight = 1; + + mColor = lcVector4(0.0f, 0.0f, 0.0f, 0.0f); + mWorldMatrix = lcMatrix44Identity(); + mViewMatrix = lcMatrix44Identity(); + mProjectionMatrix = lcMatrix44Identity(); + mViewProjectionMatrix = lcMatrix44Identity(); + mColorDirty = false; + mWorldMatrixDirty = false; + mViewMatrixDirty = false; + mProjectionMatrixDirty = false; + mViewProjectionMatrixDirty = false; + + mProgramType = LC_NUM_PROGRAMS; +} + +lcContext::~lcContext() +{ +} + +void lcContext::CreateShaderPrograms() +{ + const char* VertexShaders[LC_NUM_PROGRAMS] = + { + // LC_PROGRAM_SIMPLE + "#version 110\n" + "attribute vec3 VertexPosition;\n" + "uniform mat4 WorldViewProjectionMatrix;\n" + "void main()\n" + "{\n" + " gl_Position = WorldViewProjectionMatrix * vec4(VertexPosition, 1.0);\n" + "}\n", + // LC_PROGRAM_TEXTURE + "#version 110\n" + "attribute vec3 VertexPosition;\n" + "attribute vec2 VertexTexCoord;\n" + "varying vec2 PixelTexCoord;\n" + "uniform mat4 WorldViewProjectionMatrix;\n" + "void main()\n" + "{\n" + " gl_Position = WorldViewProjectionMatrix * vec4(VertexPosition, 1.0);\n" + " PixelTexCoord = VertexTexCoord;\n" + "}\n", + // LC_PROGRAM_VERTEX_COLOR + "#version 110\n" + "attribute vec3 VertexPosition;\n" + "attribute vec4 VertexColor;\n" + "varying vec4 PixelColor;\n" + "uniform mat4 WorldViewProjectionMatrix;\n" + "void main()\n" + "{\n" + " gl_Position = WorldViewProjectionMatrix * vec4(VertexPosition, 1.0);\n" + " PixelColor = VertexColor;\n" + "}\n" + }; + + const char* FragmentShaders[LC_NUM_PROGRAMS] = + { + // LC_PROGRAM_SIMPLE + "#version 110\n" + "uniform vec4 Color;\n" + "void main()\n" + "{\n" + " gl_FragColor = Color;\n" + "}\n", + // LC_PROGRAM_TEXTURE + "#version 110\n" + "varying vec2 PixelTexCoord;\n" + "uniform vec4 Color;\n" + "uniform sampler2D Texture;\n" + "void main()\n" + "{\n" + " gl_FragColor = texture2D(Texture, PixelTexCoord) * Color;\n" + "}\n", + // LC_PROGRAM_VERTEX_COLOR + "#version 110\n" + "varying vec4 PixelColor;\n" + "void main()\n" + "{\n" + " gl_FragColor = PixelColor;\n" + "}\n" + }; + + for (int ProgramIdx = 0; ProgramIdx < LC_NUM_PROGRAMS; ProgramIdx++) + { + GLuint VertexShader = glCreateShader(GL_VERTEX_SHADER); + glShaderSource(VertexShader, 1, &VertexShaders[ProgramIdx], NULL); + glCompileShader(VertexShader); + +#ifndef QT_NO_DEBUG + GLint VertexShaderCompiled = 0; + glGetShaderiv(VertexShader, GL_COMPILE_STATUS, &VertexShaderCompiled); + + if (VertexShaderCompiled == GL_FALSE) + { + GLint Length = 0; + glGetShaderiv(VertexShader, GL_INFO_LOG_LENGTH, &Length); + + QByteArray InfoLog; + InfoLog.resize(Length); + glGetShaderInfoLog(VertexShader, Length, &Length, InfoLog.data()); + + qDebug() << InfoLog; + } +#endif + + GLuint FragmentShader = glCreateShader(GL_FRAGMENT_SHADER); + glShaderSource(FragmentShader, 1, &FragmentShaders[ProgramIdx], NULL); + glCompileShader(FragmentShader); + +#ifndef QT_NO_DEBUG + GLint FragmentShaderCompiled = 0; + glGetShaderiv(FragmentShader, GL_COMPILE_STATUS, &FragmentShaderCompiled); + + if (FragmentShaderCompiled == GL_FALSE) + { + GLint Length = 0; + glGetShaderiv(FragmentShader, GL_INFO_LOG_LENGTH, &Length); + + QByteArray InfoLog; + InfoLog.resize(Length); + glGetShaderInfoLog(FragmentShader, Length, &Length, InfoLog.data()); + + qDebug() << InfoLog; + } +#endif + + GLuint Program = glCreateProgram(); + + glAttachShader(Program, VertexShader); + glAttachShader(Program, FragmentShader); + + glBindAttribLocation(Program, LC_ATTRIB_POSITION, "VertexPosition"); + glBindAttribLocation(Program, LC_ATTRIB_TEXCOORD, "VertexTexCoord"); + glBindAttribLocation(Program, LC_ATTRIB_COLOR, "VertexColor"); + + glLinkProgram(Program); + + glDetachShader(Program, VertexShader); + glDetachShader(Program, FragmentShader); + glDeleteShader(VertexShader); + glDeleteShader(FragmentShader); + + GLint IsLinked = 0; + glGetProgramiv(Program, GL_LINK_STATUS, &IsLinked); + if (IsLinked == GL_FALSE) + { + GLint Length = 0; + glGetProgramiv(Program, GL_INFO_LOG_LENGTH, &Length); + + QByteArray InfoLog; + InfoLog.resize(Length); + glGetProgramInfoLog(Program, Length, &Length, InfoLog.data()); + + glDeleteProgram(Program); + Program = 0; + } + + mPrograms[ProgramIdx].Object = Program; + mPrograms[ProgramIdx].MatrixLocation = glGetUniformLocation(Program, "WorldViewProjectionMatrix"); + mPrograms[ProgramIdx].ColorLocation = glGetUniformLocation(Program, "Color"); + } +} + +void lcContext::CreateResources() +{ + if (!gSupportsShaderObjects) + return; + + CreateShaderPrograms(); +} + +void lcContext::DestroyResources() +{ + if (!gSupportsShaderObjects) + return; + + for (int ProgramIdx = 0; ProgramIdx < LC_NUM_PROGRAMS; ProgramIdx++) + glDeleteProgram(mPrograms[ProgramIdx].Object); +} + +void lcContext::SetDefaultState() +{ + glEnable(GL_DEPTH_TEST); + glDepthFunc(GL_LEQUAL); + + glEnable(GL_POLYGON_OFFSET_FILL); + glPolygonOffset(0.5f, 0.1f); + + if (gSupportsVertexBufferObject) + { + glBindBuffer(GL_ARRAY_BUFFER_ARB, 0); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER_ARB, 0); + } + + if (gSupportsShaderObjects) + { + glEnableVertexAttribArray(LC_ATTRIB_POSITION); + glDisableVertexAttribArray(LC_ATTRIB_TEXCOORD); + glDisableVertexAttribArray(LC_ATTRIB_COLOR); + } + else + { + glEnableClientState(GL_VERTEX_ARRAY); + glDisableClientState(GL_TEXTURE_COORD_ARRAY); + glDisableClientState(GL_COLOR_ARRAY); + + glVertexPointer(3, GL_FLOAT, 0, NULL); + glTexCoordPointer(2, GL_FLOAT, 0, NULL); + glColorPointer(4, GL_FLOAT, 0, NULL); + } + + mTexCoordEnabled = false; + mColorEnabled = false; + + mVertexBufferObject = 0; + mIndexBufferObject = 0; + mVertexBufferPointer = NULL; + mIndexBufferPointer = NULL; + mVertexBufferOffset = (char*)~0; + + glDisable(GL_TEXTURE_2D); + mTexture = NULL; + + glLineWidth(1.0f); + mLineWidth = 1.0f; + + if (gSupportsShaderObjects) + { + glUseProgram(0); + mProgramType = LC_NUM_PROGRAMS; + } + else + { + glMatrixMode(GL_MODELVIEW); + mMatrixMode = GL_MODELVIEW; + } +} + +void lcContext::SetProgram(lcProgramType ProgramType) +{ + if (!gSupportsShaderObjects || mProgramType == ProgramType) + return; + + glUseProgram(mPrograms[ProgramType].Object); + mProgramType = ProgramType; + mColorDirty = true; + mWorldMatrixDirty = true; +} + +void lcContext::SetViewport(int x, int y, int Width, int Height) +{ + if (mViewportX == x && mViewportY == y && mViewportWidth == Width && mViewportHeight == Height) + return; + + glViewport(x, y, Width, Height); + + mViewportX = x; + mViewportY = y; + mViewportWidth = Width; + mViewportHeight = Height; +} + +void lcContext::SetLineWidth(float LineWidth) +{ + if (LineWidth == mLineWidth) + return; + + glLineWidth(LineWidth); + mLineWidth = LineWidth; +} + +void lcContext::SetColor(float Red, float Green, float Blue, float Alpha) +{ + SetColor(lcVector4(Red, Green, Blue, Alpha)); +} + +void lcContext::SetColorIndex(int ColorIndex) +{ + SetColor(gColorList[ColorIndex].Value); +} + +void lcContext::SetColorIndexTinted(int ColorIndex, lcInterfaceColor InterfaceColor) +{ + SetColor((gColorList[ColorIndex].Value + gInterfaceColors[InterfaceColor]) * 0.5f); +} + +void lcContext::SetEdgeColorIndex(int ColorIndex) +{ + SetColor(gColorList[ColorIndex].Edge); +} + +void lcContext::SetInterfaceColor(lcInterfaceColor InterfaceColor) +{ + SetColor(gInterfaceColors[InterfaceColor]); +} + +bool lcContext::BeginRenderToTexture(int Width, int Height) +{ + if (gSupportsFramebufferObjectARB) + { + glGenFramebuffers(1, &mFramebufferObject); + glGenTextures(1, &mFramebufferTexture); + glGenRenderbuffers(1, &mDepthRenderbufferObject); + + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, mFramebufferObject); + + glBindTexture(GL_TEXTURE_2D, mFramebufferTexture); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, Width, Height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); + glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mFramebufferTexture, 0); + + glBindRenderbuffer(GL_RENDERBUFFER, mDepthRenderbufferObject); + glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, Width, Height); + glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, mDepthRenderbufferObject); + + glBindTexture(GL_TEXTURE_2D, 0); + glBindFramebuffer(GL_FRAMEBUFFER, mFramebufferObject); + + if (glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) + { + EndRenderToTexture(); + return false; + } + + return true; + } + + if (gSupportsFramebufferObjectEXT) + { + glGenFramebuffersEXT(1, &mFramebufferObject); + glGenTextures(1, &mFramebufferTexture); + + glBindTexture(GL_TEXTURE_2D, mFramebufferTexture); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, Width, Height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); + + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, mFramebufferObject); + glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, mFramebufferTexture, 0); + + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, mFramebufferObject); + + glGenRenderbuffersEXT(1, &mDepthRenderbufferObject); + glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, mDepthRenderbufferObject); + glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT24, Width, Height); + + glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, mDepthRenderbufferObject); + + glBindTexture(GL_TEXTURE_2D, 0); + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, mFramebufferObject); + + if (glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT) != GL_FRAMEBUFFER_COMPLETE_EXT) + { + EndRenderToTexture(); + return false; + } + + return true; + } + + return false; +} + +void lcContext::EndRenderToTexture() +{ + if (gSupportsFramebufferObjectARB) + { + glDeleteFramebuffers(1, &mFramebufferObject); + mFramebufferObject = 0; + glDeleteTextures(1, &mFramebufferTexture); + mFramebufferTexture = 0; + glDeleteRenderbuffers(1, &mDepthRenderbufferObject); + mDepthRenderbufferObject = 0; + + return; + } + + if (gSupportsFramebufferObjectEXT) + { + glDeleteFramebuffersEXT(1, &mFramebufferObject); + mFramebufferObject = 0; + glDeleteTextures(1, &mFramebufferTexture); + mFramebufferTexture = 0; + glDeleteRenderbuffersEXT(1, &mDepthRenderbufferObject); + mDepthRenderbufferObject = 0; + } +} + +bool lcContext::SaveRenderToTextureImage(const QString& FileName, int Width, int Height) +{ + lcuint8* Buffer = (lcuint8*)malloc(Width * Height * 4); + + glFinish(); + glReadPixels(0, 0, Width, Height, GL_RGBA, GL_UNSIGNED_BYTE, Buffer); + + for (int y = 0; y < (Height + 1) / 2; y++) + { + lcuint8* Top = Buffer + ((Height - y - 1) * Width * 4); + lcuint8* Bottom = Buffer + y * Width * 4; + + for (int x = 0; x < Width; x++) + { + lcuint8 Red = Top[0]; + lcuint8 Green = Top[1]; + lcuint8 Blue = Top[2]; + lcuint8 Alpha = Top[3]; + + Top[0] = Bottom[2]; + Top[1] = Bottom[1]; + Top[2] = Bottom[0]; + Top[3] = Bottom[3]; + + Bottom[0] = Blue; + Bottom[1] = Green; + Bottom[2] = Red; + Bottom[3] = Alpha; + + Top += 4; + Bottom +=4; + } + } + + QImageWriter Writer(FileName); + bool Result = Writer.write(QImage(Buffer, Width, Height, QImage::Format_ARGB32)); + + if (!Result) + QMessageBox::information(gMainWindow, tr("Error"), tr("Error writing to file '%1':\n%2").arg(FileName, Writer.errorString())); + + free(Buffer); + + return Result; +} + +lcVertexBuffer lcContext::CreateVertexBuffer(int Size, const void* Data) +{ + lcVertexBuffer VertexBuffer; + + if (gSupportsVertexBufferObject) + { + glGenBuffers(1, &VertexBuffer.Object); + glBindBuffer(GL_ARRAY_BUFFER_ARB, VertexBuffer.Object); + glBufferData(GL_ARRAY_BUFFER_ARB, Size, Data, GL_STATIC_DRAW_ARB); + + glBindBuffer(GL_ARRAY_BUFFER_ARB, 0); // context remove + mVertexBufferObject = 0; + } + else + { + VertexBuffer.Pointer = malloc(Size); + memcpy(VertexBuffer.Pointer, Data, Size); + } + + return VertexBuffer; +} + +void lcContext::DestroyVertexBuffer(lcVertexBuffer& VertexBuffer) +{ + if (!VertexBuffer.IsValid()) + return; + + if (gSupportsVertexBufferObject) + { + if (mVertexBufferObject == VertexBuffer.Object) + { + glBindBuffer(GL_ARRAY_BUFFER_ARB, 0); + mVertexBufferObject = 0; + } + + glDeleteBuffers(1, &VertexBuffer.Object); + } + else + { + free(VertexBuffer.Pointer); + } + + VertexBuffer.Pointer = NULL; +} + +lcIndexBuffer lcContext::CreateIndexBuffer(int Size, const void* Data) +{ + lcIndexBuffer IndexBuffer; + + if (gSupportsVertexBufferObject) + { + glGenBuffers(1, &IndexBuffer.Object); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER_ARB, IndexBuffer.Object); + glBufferData(GL_ELEMENT_ARRAY_BUFFER_ARB, Size, Data, GL_STATIC_DRAW_ARB); + + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER_ARB, 0); // context remove + mIndexBufferObject = 0; + } + else + { + IndexBuffer.Pointer = malloc(Size); + memcpy(IndexBuffer.Pointer, Data, Size); + } + + return IndexBuffer; +} + +void lcContext::DestroyIndexBuffer(lcIndexBuffer& IndexBuffer) +{ + if (!IndexBuffer.IsValid()) + return; + + if (gSupportsVertexBufferObject) + { + if (mIndexBufferObject == IndexBuffer.Object) + { + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER_ARB, 0); + mIndexBufferObject = 0; + } + + glDeleteBuffers(1, &IndexBuffer.Object); + } + else + { + free(IndexBuffer.Pointer); + } + + IndexBuffer.Pointer = NULL; +} + +void lcContext::ClearVertexBuffer() +{ + mVertexBufferPointer = NULL; + mVertexBufferOffset = (char*)~0; + + if (mVertexBufferObject) + { + glBindBuffer(GL_ARRAY_BUFFER_ARB, 0); + mVertexBufferObject = 0; + } + + if (mTexCoordEnabled) + glDisableClientState(GL_TEXTURE_COORD_ARRAY); + + if (mColorEnabled) + glDisableClientState(GL_COLOR_ARRAY); +} + +void lcContext::SetVertexBuffer(lcVertexBuffer VertexBuffer) +{ + if (gSupportsVertexBufferObject) + { + GLuint VertexBufferObject = VertexBuffer.Object; + mVertexBufferPointer = NULL; + + if (VertexBufferObject != mVertexBufferObject) + { + glBindBuffer(GL_ARRAY_BUFFER_ARB, VertexBufferObject); + mVertexBufferObject = VertexBufferObject; + mVertexBufferOffset = (char*)~0; + } + } + else + { + mVertexBufferPointer = (char*)VertexBuffer.Pointer; + mVertexBufferOffset = (char*)~0; + } +} + +void lcContext::SetVertexBufferPointer(const void* VertexBuffer) +{ + if (gSupportsVertexBufferObject && mVertexBufferObject) + { + glBindBuffer(GL_ARRAY_BUFFER_ARB, 0); + mVertexBufferObject = 0; + } + + mVertexBufferPointer = (char*)VertexBuffer; + mVertexBufferOffset = (char*)~0; +} + +void lcContext::SetVertexFormat(int BufferOffset, int PositionSize, int TexCoordSize, int ColorSize) +{ + int VertexSize = (PositionSize + TexCoordSize + ColorSize) * sizeof(float); + char* VertexBufferPointer = mVertexBufferPointer + BufferOffset; + + if (mVertexBufferOffset != VertexBufferPointer) + { + if (gSupportsShaderObjects) + glVertexAttribPointer(LC_ATTRIB_POSITION, PositionSize, GL_FLOAT, false, VertexSize, VertexBufferPointer); + else + glVertexPointer(PositionSize, GL_FLOAT, VertexSize, VertexBufferPointer); + + mVertexBufferOffset = VertexBufferPointer; + } + + if (TexCoordSize) + { + if (gSupportsShaderObjects) + { + glVertexAttribPointer(LC_ATTRIB_TEXCOORD, TexCoordSize, GL_FLOAT, false, VertexSize, VertexBufferPointer + PositionSize * sizeof(float)); + + if (!mTexCoordEnabled) + { + glEnableVertexAttribArray(LC_ATTRIB_TEXCOORD); + mTexCoordEnabled = true; + } + } + else + { + glTexCoordPointer(TexCoordSize, GL_FLOAT, VertexSize, VertexBufferPointer + PositionSize * sizeof(float)); + + if (!mTexCoordEnabled) + { + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + mTexCoordEnabled = true; + } + } + } + else if (mTexCoordEnabled) + { + if (gSupportsShaderObjects) + glDisableVertexAttribArray(LC_ATTRIB_TEXCOORD); + else + glDisableClientState(GL_TEXTURE_COORD_ARRAY); + mTexCoordEnabled = false; + } + + if (ColorSize) + { + if (gSupportsShaderObjects) + { + glVertexAttribPointer(LC_ATTRIB_COLOR, ColorSize, GL_FLOAT, false, VertexSize, VertexBufferPointer + (PositionSize + TexCoordSize) * sizeof(float)); + + if (!mColorEnabled) + { + glEnableVertexAttribArray(LC_ATTRIB_COLOR); + mColorEnabled = true; + } + } + else + { + glColorPointer(ColorSize, GL_FLOAT, VertexSize, VertexBufferPointer + (PositionSize + TexCoordSize) * sizeof(float)); + + if (!mColorEnabled) + { + glEnableClientState(GL_COLOR_ARRAY); + mColorEnabled = true; + } + } + } + else if (mColorEnabled) + { + if (gSupportsShaderObjects) + glDisableVertexAttribArray(LC_ATTRIB_COLOR); + else + glDisableClientState(GL_COLOR_ARRAY); + mColorEnabled = false; + } +} + +void lcContext::ClearIndexBuffer() +{ + if (mIndexBufferObject) + { + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER_ARB, 0); + mIndexBufferObject = 0; + } +} + +void lcContext::SetIndexBuffer(lcIndexBuffer IndexBuffer) +{ + if (gSupportsVertexBufferObject) + { + GLuint IndexBufferObject = IndexBuffer.Object; + mIndexBufferPointer = NULL; + + if (IndexBufferObject != mIndexBufferObject) + { + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER_ARB, IndexBufferObject); + mIndexBufferObject = IndexBufferObject; + } + } + else + { + mIndexBufferPointer = (char*)IndexBuffer.Pointer; + } +} + +void lcContext::SetIndexBufferPointer(const void* IndexBuffer) +{ + if (mIndexBufferObject) + { + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER_ARB, 0); + mIndexBufferObject = 0; + } + + mIndexBufferPointer = (char*)IndexBuffer; +} + +void lcContext::BindMesh(lcMesh* Mesh) +{ + lcPiecesLibrary* Library = lcGetPiecesLibrary(); + + if (Mesh->mVertexCacheOffset != -1) + { + GLuint VertexBufferObject = Library->mVertexBuffer.Object; + GLuint IndexBufferObject = Library->mIndexBuffer.Object; + + if (VertexBufferObject != mVertexBufferObject) + { + glBindBuffer(GL_ARRAY_BUFFER_ARB, VertexBufferObject); + mVertexBufferObject = VertexBufferObject; + mVertexBufferPointer = NULL; + mVertexBufferOffset = (char*)~0; + } + + if (IndexBufferObject != mIndexBufferObject) + { + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER_ARB, IndexBufferObject); + mIndexBufferObject = IndexBufferObject; + mIndexBufferPointer = NULL; + } + } + else + { + if (mVertexBufferObject) + { + glBindBuffer(GL_ARRAY_BUFFER_ARB, 0); + mVertexBufferObject = 0; + } + + if (mIndexBufferObject) + { + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER_ARB, 0); + mIndexBufferObject = 0; + } + + mVertexBufferPointer = (char*)Mesh->mVertexData; + mIndexBufferPointer = (char*)Mesh->mIndexData; + mVertexBufferOffset = (char*)~0; + } +} + +void lcContext::UnbindMesh() +{ + if (mTexture) + { + glDisableClientState(GL_TEXTURE_COORD_ARRAY); + glDisable(GL_TEXTURE_2D); + mTexture = NULL; + } + + if (gSupportsVertexBufferObject) + { + glBindBuffer(GL_ARRAY_BUFFER_ARB, 0); + mVertexBufferObject = 0; + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER_ARB, 0); + mIndexBufferObject = 0; + } + + mVertexBufferPointer = NULL; + mIndexBufferPointer = NULL; + + if (gSupportsShaderObjects) + { + glDisableVertexAttribArray(LC_ATTRIB_TEXCOORD); + glDisableVertexAttribArray(LC_ATTRIB_COLOR); + } + else + { + glVertexPointer(3, GL_FLOAT, 0, NULL); + glTexCoordPointer(2, GL_FLOAT, 0, NULL); + } + mTexCoordEnabled = false; + mColorEnabled = false; +} + +void lcContext::FlushState() +{ + if (gSupportsShaderObjects) + { + if (mWorldMatrixDirty || mViewMatrixDirty || mProjectionMatrixDirty) + { + if (mViewProjectionMatrixDirty) + { + mViewProjectionMatrix = lcMul(mViewMatrix, mProjectionMatrix); + mViewProjectionMatrixDirty = false; + } + + glUniformMatrix4fv(mPrograms[mProgramType].MatrixLocation, 1, false, lcMul(mWorldMatrix, mViewProjectionMatrix)); + mWorldMatrixDirty = false; + mViewMatrixDirty = false; + mProjectionMatrixDirty = false; + } + + if (mColorDirty && mPrograms[mProgramType].ColorLocation != -1) + { + glUniform4fv(mPrograms[mProgramType].ColorLocation, 1, mColor); + mColorDirty = false; + } + } + else + { + glColor4fv(mColor); + + if (mWorldMatrixDirty || mViewMatrixDirty) + { + if (mMatrixMode != GL_MODELVIEW) + { + glMatrixMode(GL_MODELVIEW); + mMatrixMode = GL_MODELVIEW; + } + + glLoadMatrixf(lcMul(mWorldMatrix, mViewMatrix)); + mWorldMatrixDirty = false; + mViewMatrixDirty = false; + } + + if (mProjectionMatrixDirty) + { + if (mMatrixMode != GL_PROJECTION) + { + glMatrixMode(GL_PROJECTION); + mMatrixMode = GL_PROJECTION; + } + + glLoadMatrixf(mProjectionMatrix); + mProjectionMatrixDirty = false; + } + } +} + +void lcContext::DrawPrimitives(GLenum Mode, GLint First, GLsizei Count) +{ + FlushState(); + glDrawArrays(Mode, First, Count); +} + +void lcContext::DrawIndexedPrimitives(GLenum Mode, GLsizei Count, GLenum Type, int Offset) +{ + FlushState(); + glDrawElements(Mode, Count, Type, mIndexBufferPointer + Offset); +} + +void lcContext::DrawMeshSection(lcMesh* Mesh, lcMeshSection* Section) +{ + lcTexture* Texture = Section->Texture; + int VertexBufferOffset = Mesh->mVertexCacheOffset != -1 ? Mesh->mVertexCacheOffset : 0; + int IndexBufferOffset = Mesh->mIndexCacheOffset != -1 ? Mesh->mIndexCacheOffset : 0; + + if (!Texture) + { + SetProgram(LC_PROGRAM_SIMPLE); + SetVertexFormat(VertexBufferOffset, 3, 0, 0); + + if (mTexture) + { + glDisable(GL_TEXTURE_2D); + mTexture = NULL; + } + } + else + { + VertexBufferOffset += Mesh->mNumVertices * sizeof(lcVertex); + SetProgram(LC_PROGRAM_TEXTURE); + SetVertexFormat(VertexBufferOffset, 3, 2, 0); + + if (Texture != mTexture) + { + glBindTexture(GL_TEXTURE_2D, Texture->mTexture); + + if (!mTexture) + { + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL); + glEnable(GL_TEXTURE_2D); + } + + mTexture = Texture; + } + } + + bool DrawConditional = false; + + if (Section->PrimitiveType != LC_MESH_CONDITIONAL_LINES) + { + GLenum PrimitiveType = (Section->PrimitiveType == LC_MESH_TRIANGLES || Section->PrimitiveType == LC_MESH_TEXTURED_TRIANGLES) ? GL_TRIANGLES : GL_LINES; + DrawIndexedPrimitives(PrimitiveType, Section->NumIndices, Mesh->mIndexType, IndexBufferOffset + Section->IndexOffset); + } + else if (DrawConditional) + { + FlushState(); + lcMatrix44 WorldViewProjectionMatrix = lcMul(mWorldMatrix, mViewProjectionMatrix); + float* VertexBuffer = (float*)Mesh->mVertexData; + + if (Mesh->mIndexType == GL_UNSIGNED_SHORT) + { + lcuint16* Indices = (lcuint16*)((char*)Mesh->mIndexData + Section->IndexOffset); + + for (int i = 0; i < Section->NumIndices; i += 4) + { + lcVector3 p1 = lcMul31(lcVector3(VertexBuffer[Indices[i] * 3], VertexBuffer[Indices[i] * 3 + 1], VertexBuffer[Indices[i] * 3 + 2]), WorldViewProjectionMatrix); + lcVector3 p2 = lcMul31(lcVector3(VertexBuffer[Indices[i + 1] * 3], VertexBuffer[Indices[i + 1] * 3 + 1], VertexBuffer[Indices[i + 1] * 3 + 2]), WorldViewProjectionMatrix); + lcVector3 p3 = lcMul31(lcVector3(VertexBuffer[Indices[i + 2] * 3], VertexBuffer[Indices[i + 2] * 3 + 1], VertexBuffer[Indices[i + 2] * 3 + 2]), WorldViewProjectionMatrix); + lcVector3 p4 = lcMul31(lcVector3(VertexBuffer[Indices[i + 3] * 3], VertexBuffer[Indices[i + 3] * 3 + 1], VertexBuffer[Indices[i + 3] * 3 + 2]), WorldViewProjectionMatrix); + + if (((p1.y - p2.y) * (p3.x - p1.x) + (p2.x - p1.x) * (p3.y - p1.y)) * ((p1.y - p2.y) * (p4.x - p1.x) + (p2.x - p1.x) * (p4.y - p1.y)) >= 0) + DrawIndexedPrimitives(GL_LINES, 2, Mesh->mIndexType, IndexBufferOffset + Section->IndexOffset + i * sizeof(lcuint16)); + } + } + else + { + lcuint32* Indices = (lcuint32*)((char*)Mesh->mIndexData + Section->IndexOffset); + + for (int i = 0; i < Section->NumIndices; i += 4) + { + lcVector3 p1 = lcMul31(lcVector3(VertexBuffer[Indices[i] * 3], VertexBuffer[Indices[i] * 3 + 1], VertexBuffer[Indices[i] * 3 + 2]), WorldViewProjectionMatrix); + lcVector3 p2 = lcMul31(lcVector3(VertexBuffer[Indices[i + 1] * 3], VertexBuffer[Indices[i + 1] * 3 + 1], VertexBuffer[Indices[i + 1] * 3 + 2]), WorldViewProjectionMatrix); + lcVector3 p3 = lcMul31(lcVector3(VertexBuffer[Indices[i + 2] * 3], VertexBuffer[Indices[i + 2] * 3 + 1], VertexBuffer[Indices[i + 2] * 3 + 2]), WorldViewProjectionMatrix); + lcVector3 p4 = lcMul31(lcVector3(VertexBuffer[Indices[i + 3] * 3], VertexBuffer[Indices[i + 3] * 3 + 1], VertexBuffer[Indices[i + 3] * 3 + 2]), WorldViewProjectionMatrix); + + if (((p1.y - p2.y) * (p3.x - p1.x) + (p2.x - p1.x) * (p3.y - p1.y)) * ((p1.y - p2.y) * (p4.x - p1.x) + (p2.x - p1.x) * (p4.y - p1.y)) >= 0) + DrawIndexedPrimitives(GL_LINES, 2, Mesh->mIndexType, IndexBufferOffset + Section->IndexOffset + i * sizeof(lcuint32)); + } + } + } +} + +void lcContext::DrawOpaqueMeshes(const lcArray& OpaqueMeshes) +{ + bool DrawLines = lcGetPreferences().mDrawEdgeLines; + + lcGetPiecesLibrary()->UpdateBuffers(this); // TODO: find a better place for this update + + for (int MeshIdx = 0; MeshIdx < OpaqueMeshes.GetSize(); MeshIdx++) + { + const lcRenderMesh& RenderMesh = OpaqueMeshes[MeshIdx]; + lcMesh* Mesh = RenderMesh.Mesh; + int LodIndex = RenderMesh.LodIndex; + + BindMesh(Mesh); + SetWorldMatrix(RenderMesh.WorldMatrix); + + for (int SectionIdx = 0; SectionIdx < Mesh->mLods[LodIndex].NumSections; SectionIdx++) + { + lcMeshSection* Section = &Mesh->mLods[LodIndex].Sections[SectionIdx]; + int ColorIndex = Section->ColorIndex; + + if (Section->PrimitiveType == LC_MESH_TRIANGLES || Section->PrimitiveType == LC_MESH_TEXTURED_TRIANGLES) + { + if (ColorIndex == gDefaultColor) + ColorIndex = RenderMesh.ColorIndex; + + if (lcIsColorTranslucent(ColorIndex)) + continue; + + switch (RenderMesh.State) + { + case LC_RENDERMESH_NONE: + SetColorIndex(ColorIndex); + break; + + case LC_RENDERMESH_SELECTED: + SetColorIndexTinted(ColorIndex, LC_COLOR_SELECTED); + break; + + case LC_RENDERMESH_FOCUSED: + SetColorIndexTinted(ColorIndex, LC_COLOR_FOCUSED); + break; + } + } + else + { + switch (RenderMesh.State) + { + case LC_RENDERMESH_NONE: + if (DrawLines) + { + if (ColorIndex == gEdgeColor) + SetEdgeColorIndex(RenderMesh.ColorIndex); + else + SetColorIndex(ColorIndex); + } + else + continue; + break; + + case LC_RENDERMESH_SELECTED: + SetInterfaceColor(LC_COLOR_SELECTED); + break; + + case LC_RENDERMESH_FOCUSED: + SetInterfaceColor(LC_COLOR_FOCUSED); + break; + } + } + + DrawMeshSection(Mesh, Section); + } + } +} + +void lcContext::DrawTranslucentMeshes(const lcArray& TranslucentMeshes) +{ + if (TranslucentMeshes.IsEmpty()) + return; + + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glEnable(GL_BLEND); + glDepthMask(GL_FALSE); + + for (int MeshIdx = 0; MeshIdx < TranslucentMeshes.GetSize(); MeshIdx++) + { + const lcRenderMesh& RenderMesh = TranslucentMeshes[MeshIdx]; + lcMesh* Mesh = RenderMesh.Mesh; + int LodIndex = RenderMesh.LodIndex; + + BindMesh(Mesh); + SetWorldMatrix(RenderMesh.WorldMatrix); + + for (int SectionIdx = 0; SectionIdx < Mesh->mLods[LodIndex].NumSections; SectionIdx++) + { + lcMeshSection* Section = &Mesh->mLods[LodIndex].Sections[SectionIdx]; + int ColorIndex = Section->ColorIndex; + + if (Section->PrimitiveType != LC_MESH_TRIANGLES) + continue; + + if (ColorIndex == gDefaultColor) + ColorIndex = RenderMesh.ColorIndex; + + if (!lcIsColorTranslucent(ColorIndex)) + continue; + + switch (RenderMesh.State) + { + case LC_RENDERMESH_NONE: + SetColorIndex(ColorIndex); + break; + + case LC_RENDERMESH_SELECTED: + SetColorIndexTinted(ColorIndex, LC_COLOR_SELECTED); + break; + + case LC_RENDERMESH_FOCUSED: + SetColorIndexTinted(ColorIndex, LC_COLOR_FOCUSED); + break; + } + + DrawMeshSection(Mesh, Section); + } + } + + glDepthMask(GL_TRUE); + glDisable(GL_BLEND); +} + +void lcContext::DrawInterfaceObjects(const lcArray& InterfaceObjects) +{ + for (int ObjectIdx = 0; ObjectIdx < InterfaceObjects.GetSize(); ObjectIdx++) + InterfaceObjects[ObjectIdx]->DrawInterface(this); +} diff --git a/common/lc_context.h b/common/lc_context.h index 6e603929..3204946a 100644 --- a/common/lc_context.h +++ b/common/lc_context.h @@ -1,213 +1,213 @@ -#ifndef _LC_CONTEXT_H_ -#define _LC_CONTEXT_H_ - -#include "lc_array.h" -#include "lc_math.h" -#include "lc_colors.h" -#include "lc_mesh.h" - -class lcScene -{ -public: - lcScene(); - - void Begin(const lcMatrix44& ViewMatrix); - void End(); - - lcMatrix44 mViewMatrix; - lcArray mOpaqueMeshes; - lcArray mTranslucentMeshes; - lcArray mInterfaceObjects; -}; - -class lcVertexBuffer -{ -public: - lcVertexBuffer() - : Pointer(NULL) - { - } - - bool IsValid() const - { - return Pointer != NULL; - } - - union - { - GLuint Object; - void* Pointer; - }; -}; - -class lcIndexBuffer -{ -public: - lcIndexBuffer() - : Pointer(NULL) - { - } - - bool IsValid() const - { - return Pointer != NULL; - } - - union - { - GLuint Object; - void* Pointer; - }; -}; - -enum lcProgramType -{ - LC_PROGRAM_SIMPLE, - LC_PROGRAM_TEXTURE, - LC_PROGRAM_VERTEX_COLOR, - LC_NUM_PROGRAMS -}; - -enum lcProgramAttrib -{ - LC_ATTRIB_POSITION, - LC_ATTRIB_TEXCOORD, - LC_ATTRIB_COLOR -}; - -struct lcProgram -{ - GLuint Object; - GLint MatrixLocation; - GLint ColorLocation; -}; - -class lcContext -{ -public: - lcContext(); - ~lcContext(); - - int GetViewportWidth() const - { - return mViewportWidth; - } - - int GetViewportHeight() const - { - return mViewportHeight; - } - - static void CreateResources(); - static void DestroyResources(); - - void SetDefaultState(); - - void SetWorldMatrix(const lcMatrix44& WorldMatrix) - { - mWorldMatrix = WorldMatrix; - mWorldMatrixDirty = true; - } - - void SetViewMatrix(const lcMatrix44& ViewMatrix) - { - mViewMatrix = ViewMatrix; - mViewMatrixDirty = true; - mViewProjectionMatrixDirty = true; - } - - void SetProjectionMatrix(const lcMatrix44& ProjectionMatrix) - { - mProjectionMatrix = ProjectionMatrix; - mProjectionMatrixDirty = true; - mViewProjectionMatrixDirty = true; - } - - void SetProgram(lcProgramType ProgramType); - void SetViewport(int x, int y, int Width, int Height); - void SetLineWidth(float LineWidth); - - void SetColor(const lcVector4& Color) - { - mColor = Color; - mColorDirty = true; - } - - void SetColor(float Red, float Green, float Blue, float Alpha); - void SetColorIndex(int ColorIndex); - void SetColorIndexTinted(int ColorIndex, lcInterfaceColor InterfaceColor); - void SetEdgeColorIndex(int ColorIndex); - void SetInterfaceColor(lcInterfaceColor InterfaceColor); - - bool BeginRenderToTexture(int Width, int Height); - void EndRenderToTexture(); - bool SaveRenderToTextureImage(const QString& FileName, int Width, int Height); - - lcVertexBuffer CreateVertexBuffer(int Size, const void* Data); - void DestroyVertexBuffer(lcVertexBuffer& VertexBuffer); - lcIndexBuffer CreateIndexBuffer(int Size, const void* Data); - void DestroyIndexBuffer(lcIndexBuffer& IndexBuffer); - - void ClearVertexBuffer(); - void SetVertexBuffer(lcVertexBuffer VertexBuffer); - void SetVertexBufferPointer(const void* VertexBuffer); - - void ClearIndexBuffer(); - void SetIndexBuffer(lcIndexBuffer IndexBuffer); - void SetIndexBufferPointer(const void* IndexBuffer); - - void SetVertexFormat(int BufferOffset, int PositionSize, int TexCoordSize, int ColorSize); - void DrawPrimitives(GLenum Mode, GLint First, GLsizei Count); - void DrawIndexedPrimitives(GLenum Mode, GLsizei Count, GLenum Type, int Offset); - - void UnbindMesh(); - void DrawMeshSection(lcMesh* Mesh, lcMeshSection* Section); - void DrawOpaqueMeshes(const lcArray& OpaqueMeshes); - void DrawTranslucentMeshes(const lcArray& TranslucentMeshes); - void DrawInterfaceObjects(const lcArray& InterfaceObjects); - -protected: - static void CreateShaderPrograms(); - void BindMesh(lcMesh* Mesh); - void FlushState(); - - GLuint mVertexBufferObject; - GLuint mIndexBufferObject; - char* mVertexBufferPointer; - char* mIndexBufferPointer; - char* mVertexBufferOffset; - - lcProgramType mProgramType; - bool mTexCoordEnabled; - bool mColorEnabled; - - lcTexture* mTexture; - float mLineWidth; - int mMatrixMode; - - int mViewportX; - int mViewportY; - int mViewportWidth; - int mViewportHeight; - - lcVector4 mColor; - lcMatrix44 mWorldMatrix; - lcMatrix44 mViewMatrix; - lcMatrix44 mProjectionMatrix; - lcMatrix44 mViewProjectionMatrix; - bool mColorDirty; - bool mWorldMatrixDirty; - bool mViewMatrixDirty; - bool mProjectionMatrixDirty; - bool mViewProjectionMatrixDirty; - - GLuint mFramebufferObject; - GLuint mFramebufferTexture; - GLuint mDepthRenderbufferObject; - - static lcProgram mPrograms[LC_NUM_PROGRAMS]; - - Q_DECLARE_TR_FUNCTIONS(lcContext); -}; - -#endif // _LC_CONTEXT_H_ +#ifndef _LC_CONTEXT_H_ +#define _LC_CONTEXT_H_ + +#include "lc_array.h" +#include "lc_math.h" +#include "lc_colors.h" +#include "lc_mesh.h" + +class lcScene +{ +public: + lcScene(); + + void Begin(const lcMatrix44& ViewMatrix); + void End(); + + lcMatrix44 mViewMatrix; + lcArray mOpaqueMeshes; + lcArray mTranslucentMeshes; + lcArray mInterfaceObjects; +}; + +class lcVertexBuffer +{ +public: + lcVertexBuffer() + : Pointer(NULL) + { + } + + bool IsValid() const + { + return Pointer != NULL; + } + + union + { + GLuint Object; + void* Pointer; + }; +}; + +class lcIndexBuffer +{ +public: + lcIndexBuffer() + : Pointer(NULL) + { + } + + bool IsValid() const + { + return Pointer != NULL; + } + + union + { + GLuint Object; + void* Pointer; + }; +}; + +enum lcProgramType +{ + LC_PROGRAM_SIMPLE, + LC_PROGRAM_TEXTURE, + LC_PROGRAM_VERTEX_COLOR, + LC_NUM_PROGRAMS +}; + +enum lcProgramAttrib +{ + LC_ATTRIB_POSITION, + LC_ATTRIB_TEXCOORD, + LC_ATTRIB_COLOR +}; + +struct lcProgram +{ + GLuint Object; + GLint MatrixLocation; + GLint ColorLocation; +}; + +class lcContext +{ +public: + lcContext(); + ~lcContext(); + + int GetViewportWidth() const + { + return mViewportWidth; + } + + int GetViewportHeight() const + { + return mViewportHeight; + } + + static void CreateResources(); + static void DestroyResources(); + + void SetDefaultState(); + + void SetWorldMatrix(const lcMatrix44& WorldMatrix) + { + mWorldMatrix = WorldMatrix; + mWorldMatrixDirty = true; + } + + void SetViewMatrix(const lcMatrix44& ViewMatrix) + { + mViewMatrix = ViewMatrix; + mViewMatrixDirty = true; + mViewProjectionMatrixDirty = true; + } + + void SetProjectionMatrix(const lcMatrix44& ProjectionMatrix) + { + mProjectionMatrix = ProjectionMatrix; + mProjectionMatrixDirty = true; + mViewProjectionMatrixDirty = true; + } + + void SetProgram(lcProgramType ProgramType); + void SetViewport(int x, int y, int Width, int Height); + void SetLineWidth(float LineWidth); + + void SetColor(const lcVector4& Color) + { + mColor = Color; + mColorDirty = true; + } + + void SetColor(float Red, float Green, float Blue, float Alpha); + void SetColorIndex(int ColorIndex); + void SetColorIndexTinted(int ColorIndex, lcInterfaceColor InterfaceColor); + void SetEdgeColorIndex(int ColorIndex); + void SetInterfaceColor(lcInterfaceColor InterfaceColor); + + bool BeginRenderToTexture(int Width, int Height); + void EndRenderToTexture(); + bool SaveRenderToTextureImage(const QString& FileName, int Width, int Height); + + lcVertexBuffer CreateVertexBuffer(int Size, const void* Data); + void DestroyVertexBuffer(lcVertexBuffer& VertexBuffer); + lcIndexBuffer CreateIndexBuffer(int Size, const void* Data); + void DestroyIndexBuffer(lcIndexBuffer& IndexBuffer); + + void ClearVertexBuffer(); + void SetVertexBuffer(lcVertexBuffer VertexBuffer); + void SetVertexBufferPointer(const void* VertexBuffer); + + void ClearIndexBuffer(); + void SetIndexBuffer(lcIndexBuffer IndexBuffer); + void SetIndexBufferPointer(const void* IndexBuffer); + + void SetVertexFormat(int BufferOffset, int PositionSize, int TexCoordSize, int ColorSize); + void DrawPrimitives(GLenum Mode, GLint First, GLsizei Count); + void DrawIndexedPrimitives(GLenum Mode, GLsizei Count, GLenum Type, int Offset); + + void UnbindMesh(); + void DrawMeshSection(lcMesh* Mesh, lcMeshSection* Section); + void DrawOpaqueMeshes(const lcArray& OpaqueMeshes); + void DrawTranslucentMeshes(const lcArray& TranslucentMeshes); + void DrawInterfaceObjects(const lcArray& InterfaceObjects); + +protected: + static void CreateShaderPrograms(); + void BindMesh(lcMesh* Mesh); + void FlushState(); + + GLuint mVertexBufferObject; + GLuint mIndexBufferObject; + char* mVertexBufferPointer; + char* mIndexBufferPointer; + char* mVertexBufferOffset; + + lcProgramType mProgramType; + bool mTexCoordEnabled; + bool mColorEnabled; + + lcTexture* mTexture; + float mLineWidth; + int mMatrixMode; + + int mViewportX; + int mViewportY; + int mViewportWidth; + int mViewportHeight; + + lcVector4 mColor; + lcMatrix44 mWorldMatrix; + lcMatrix44 mViewMatrix; + lcMatrix44 mProjectionMatrix; + lcMatrix44 mViewProjectionMatrix; + bool mColorDirty; + bool mWorldMatrixDirty; + bool mViewMatrixDirty; + bool mProjectionMatrixDirty; + bool mViewProjectionMatrixDirty; + + GLuint mFramebufferObject; + GLuint mFramebufferTexture; + GLuint mDepthRenderbufferObject; + + static lcProgram mPrograms[LC_NUM_PROGRAMS]; + + Q_DECLARE_TR_FUNCTIONS(lcContext); +}; + +#endif // _LC_CONTEXT_H_ diff --git a/common/lc_glextensions.cpp b/common/lc_glextensions.cpp index 6384bd48..bcec0827 100644 --- a/common/lc_glextensions.cpp +++ b/common/lc_glextensions.cpp @@ -1,334 +1,334 @@ -#include "lc_global.h" -#include "lc_glextensions.h" - -bool gSupportsShaderObjects; -bool gSupportsVertexBufferObject; -bool gSupportsFramebufferObjectARB; -bool gSupportsFramebufferObjectEXT; -bool gSupportsAnisotropic; -GLfloat gMaxAnisotropy; - -#ifdef LC_LOAD_GLEXTENSIONS - -PFNGLBINDBUFFERARBPROC lcBindBufferARB; -PFNGLDELETEBUFFERSARBPROC lcDeleteBuffersARB; -PFNGLGENBUFFERSARBPROC lcGenBuffersARB; -PFNGLISBUFFERARBPROC lcIsBufferARB; -PFNGLBUFFERDATAARBPROC lcBufferDataARB; -PFNGLBUFFERSUBDATAARBPROC lcBufferSubDataARB; -PFNGLGETBUFFERSUBDATAARBPROC lcGetBufferSubDataARB; -PFNGLMAPBUFFERARBPROC lcMapBufferARB; -PFNGLUNMAPBUFFERARBPROC lcUnmapBufferARB; -PFNGLGETBUFFERPARAMETERIVARBPROC lcGetBufferParameterivARB; -PFNGLGETBUFFERPOINTERVARBPROC lcGetBufferPointervARB; - -PFNGLISRENDERBUFFERPROC lcIsRenderbuffer; -PFNGLBINDRENDERBUFFERPROC lcBindRenderbuffer; -PFNGLDELETERENDERBUFFERSPROC lcDeleteRenderbuffers; -PFNGLGENRENDERBUFFERSPROC lcGenRenderbuffers; -PFNGLRENDERBUFFERSTORAGEPROC lcRenderbufferStorage; -PFNGLGETRENDERBUFFERPARAMETERIVPROC lcGetRenderbufferParameteriv; -PFNGLISFRAMEBUFFERPROC lcIsFramebuffer; -PFNGLBINDFRAMEBUFFERPROC lcBindFramebuffer; -PFNGLDELETEFRAMEBUFFERSPROC lcDeleteFramebuffers; -PFNGLGENFRAMEBUFFERSPROC lcGenFramebuffers; -PFNGLCHECKFRAMEBUFFERSTATUSPROC lcCheckFramebufferStatus; -PFNGLFRAMEBUFFERTEXTURE1DPROC lcFramebufferTexture1D; -PFNGLFRAMEBUFFERTEXTURE2DPROC lcFramebufferTexture2D; -PFNGLFRAMEBUFFERTEXTURE3DPROC lcFramebufferTexture3D; -PFNGLFRAMEBUFFERRENDERBUFFERPROC lcFramebufferRenderbuffer; -PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC lcGetFramebufferAttachmentParameteriv; -PFNGLGENERATEMIPMAPPROC lcGenerateMipmap; -PFNGLBLITFRAMEBUFFERPROC lcBlitFramebuffer; -PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC lcRenderbufferStorageMultisample; -PFNGLFRAMEBUFFERTEXTURELAYERPROC lcFramebufferTextureLayer; - -PFNGLISRENDERBUFFEREXTPROC lcIsRenderbufferEXT; -PFNGLBINDRENDERBUFFEREXTPROC lcBindRenderbufferEXT; -PFNGLDELETERENDERBUFFERSEXTPROC lcDeleteRenderbuffersEXT; -PFNGLGENRENDERBUFFERSEXTPROC lcGenRenderbuffersEXT; -PFNGLRENDERBUFFERSTORAGEEXTPROC lcRenderbufferStorageEXT; -PFNGLGETRENDERBUFFERPARAMETERIVEXTPROC lcGetRenderbufferParameterivEXT; -PFNGLISFRAMEBUFFEREXTPROC lcIsFramebufferEXT; -PFNGLBINDFRAMEBUFFEREXTPROC lcBindFramebufferEXT; -PFNGLDELETEFRAMEBUFFERSEXTPROC lcDeleteFramebuffersEXT; -PFNGLGENFRAMEBUFFERSEXTPROC lcGenFramebuffersEXT; -PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC lcCheckFramebufferStatusEXT; -PFNGLFRAMEBUFFERTEXTURE1DEXTPROC lcFramebufferTexture1DEXT; -PFNGLFRAMEBUFFERTEXTURE2DEXTPROC lcFramebufferTexture2DEXT; -PFNGLFRAMEBUFFERTEXTURE3DEXTPROC lcFramebufferTexture3DEXT; -PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC lcFramebufferRenderbufferEXT; -PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVEXTPROC lcGetFramebufferAttachmentParameterivEXT; -PFNGLGENERATEMIPMAPEXTPROC lcGenerateMipmapEXT; - -PFNGLATTACHSHADERPROC lcAttachShader; -PFNGLBINDATTRIBLOCATIONPROC lcBindAttribLocation; -PFNGLCOMPILESHADERPROC lcCompileShader; -PFNGLCREATEPROGRAMPROC lcCreateProgram; -PFNGLCREATESHADERPROC lcCreateShader; -PFNGLDELETEPROGRAMPROC lcDeleteProgram; -PFNGLDELETESHADERPROC lcDeleteShader; -PFNGLDETACHSHADERPROC lcDetachShader; -PFNGLDISABLEVERTEXATTRIBARRAYPROC lcDisableVertexAttribArray; -PFNGLENABLEVERTEXATTRIBARRAYPROC lcEnableVertexAttribArray; -PFNGLGETACTIVEATTRIBPROC lcGetActiveAttrib; -PFNGLGETACTIVEUNIFORMPROC lcGetActiveUniform; -PFNGLGETATTACHEDSHADERSPROC lcGetAttachedShaders; -PFNGLGETATTRIBLOCATIONPROC lcGetAttribLocation; -PFNGLGETPROGRAMIVPROC lcGetProgramiv; -PFNGLGETPROGRAMINFOLOGPROC lcGetProgramInfoLog; -PFNGLGETSHADERIVPROC lcGetShaderiv; -PFNGLGETSHADERINFOLOGPROC lcGetShaderInfoLog; -PFNGLGETSHADERSOURCEPROC lcGetShaderSource; -PFNGLGETUNIFORMLOCATIONPROC lcGetUniformLocation; -PFNGLGETUNIFORMFVPROC lcGetUniformfv; -PFNGLGETUNIFORMIVPROC lcGetUniformiv; -PFNGLGETVERTEXATTRIBDVPROC lcGetVertexAttribdv; -PFNGLGETVERTEXATTRIBFVPROC lcGetVertexAttribfv; -PFNGLGETVERTEXATTRIBIVPROC lcGetVertexAttribiv; -PFNGLGETVERTEXATTRIBPOINTERVPROC lcGetVertexAttribPointerv; -PFNGLISPROGRAMPROC lcIsProgram; -PFNGLISSHADERPROC lcIsShader; -PFNGLLINKPROGRAMPROC lcLinkProgram; -PFNGLSHADERSOURCEPROC lcShaderSource; -PFNGLUSEPROGRAMPROC lcUseProgram; -PFNGLUNIFORM1FPROC lcUniform1f; -PFNGLUNIFORM2FPROC lcUniform2f; -PFNGLUNIFORM3FPROC lcUniform3f; -PFNGLUNIFORM4FPROC lcUniform4f; -PFNGLUNIFORM1IPROC lcUniform1i; -PFNGLUNIFORM2IPROC lcUniform2i; -PFNGLUNIFORM3IPROC lcUniform3i; -PFNGLUNIFORM4IPROC lcUniform4i; -PFNGLUNIFORM1FVPROC lcUniform1fv; -PFNGLUNIFORM2FVPROC lcUniform2fv; -PFNGLUNIFORM3FVPROC lcUniform3fv; -PFNGLUNIFORM4FVPROC lcUniform4fv; -PFNGLUNIFORM1IVPROC lcUniform1iv; -PFNGLUNIFORM2IVPROC lcUniform2iv; -PFNGLUNIFORM3IVPROC lcUniform3iv; -PFNGLUNIFORM4IVPROC lcUniform4iv; -PFNGLUNIFORMMATRIX2FVPROC lcUniformMatrix2fv; -PFNGLUNIFORMMATRIX3FVPROC lcUniformMatrix3fv; -PFNGLUNIFORMMATRIX4FVPROC lcUniformMatrix4fv; -PFNGLVALIDATEPROGRAMPROC lcValidateProgram; -PFNGLVERTEXATTRIBPOINTERPROC lcVertexAttribPointer; - -#endif - -static bool lcIsGLExtensionSupported(const GLubyte* Extensions, const char* Name) -{ - const GLubyte* Start; - GLubyte* Where; - GLubyte* Terminator; - - Where = (GLubyte*)strchr(Name, ' '); - if (Where || *Name == '\0') - return false; - - if (!Extensions) - return false; - - for (Start = Extensions; ;) - { - Where = (GLubyte*)strstr((const char*)Start, Name); - if (!Where) - break; - - Terminator = Where + strlen(Name); - if (Where == Start || *(Where - 1) == ' ') - if (*Terminator == ' ' || *Terminator == '\0') - return true; - - Start = Terminator; - } - - return false; -} - -#if !defined(QT_NO_DEBUG) && defined(GL_ARB_debug_output) - -static void APIENTRY lcGLDebugCallback(GLenum Source, GLenum Type, GLuint Id, GLenum Severity, GLsizei Length, const GLchar* Message, GLvoid* UserParam) -{ - Q_UNUSED(Source); - Q_UNUSED(Type); - Q_UNUSED(Id); - Q_UNUSED(Severity); - Q_UNUSED(Length); - Q_UNUSED(UserParam); - - qDebug() << Message; -} - -#endif - -void lcInitializeGLExtensions(const QGLContext* Context) -{ - const GLubyte* Extensions = glGetString(GL_EXTENSIONS); - const GLubyte* Version = glGetString(GL_VERSION); - int VersionMajor = 0, VersionMinor = 0; - - if (Version) - sscanf((const char*)Version, "%d.%d", &VersionMajor, &VersionMinor); - -#if !defined(QT_NO_DEBUG) && defined(GL_ARB_debug_output) - if (lcIsGLExtensionSupported(Extensions, "GL_KHR_debug")) - { - PFNGLDEBUGMESSAGECALLBACKARBPROC DebugMessageCallback = (PFNGLDEBUGMESSAGECALLBACKARBPROC)Context->getProcAddress("glDebugMessageCallback"); - -#ifndef GL_DEBUG_OUTPUT -#define GL_DEBUG_OUTPUT 0x92E0 -#endif - - if (DebugMessageCallback) - { - DebugMessageCallback((GLDEBUGPROCARB)&lcGLDebugCallback, NULL); - glEnable(GL_DEBUG_OUTPUT); - glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB); - } - } -#endif - - if (lcIsGLExtensionSupported(Extensions, "GL_EXT_texture_filter_anisotropic")) - { - glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &gMaxAnisotropy); - - gSupportsAnisotropic = true; - } - - // todo: check gl version and use core functions instead - if (lcIsGLExtensionSupported(Extensions, "GL_ARB_vertex_buffer_object")) - { -#ifdef LC_LOAD_GLEXTENSIONS - lcBindBufferARB = (PFNGLBINDBUFFERARBPROC)Context->getProcAddress("glBindBufferARB"); - lcDeleteBuffersARB = (PFNGLDELETEBUFFERSARBPROC)Context->getProcAddress("glDeleteBuffersARB"); - lcGenBuffersARB = (PFNGLGENBUFFERSARBPROC)Context->getProcAddress("glGenBuffersARB"); - lcIsBufferARB = (PFNGLISBUFFERARBPROC)Context->getProcAddress("glIsBufferARB"); - lcBufferDataARB = (PFNGLBUFFERDATAARBPROC)Context->getProcAddress("glBufferDataARB"); - lcBufferSubDataARB = (PFNGLBUFFERSUBDATAARBPROC)Context->getProcAddress("glBufferSubDataARB"); - lcGetBufferSubDataARB = (PFNGLGETBUFFERSUBDATAARBPROC)Context->getProcAddress("glGetBufferSubDataARB"); - lcMapBufferARB = (PFNGLMAPBUFFERARBPROC)Context->getProcAddress("glMapBufferARB"); - lcUnmapBufferARB = (PFNGLUNMAPBUFFERARBPROC)Context->getProcAddress("glUnmapBufferARB"); - lcGetBufferParameterivARB = (PFNGLGETBUFFERPARAMETERIVARBPROC)Context->getProcAddress("glGetBufferParameterivARB"); - lcGetBufferPointervARB = (PFNGLGETBUFFERPOINTERVARBPROC)Context->getProcAddress("glGetBufferPointervARB"); -#endif - gSupportsVertexBufferObject = true; - } - - // todo: check gl version - if (lcIsGLExtensionSupported(Extensions, "GL_ARB_framebuffer_object")) - { -#ifdef LC_LOAD_GLEXTENSIONS - lcIsRenderbuffer = (PFNGLISRENDERBUFFERPROC)Context->getProcAddress("glIsRenderbuffer"); - lcBindRenderbuffer = (PFNGLBINDRENDERBUFFERPROC)Context->getProcAddress("glBindRenderbuffer"); - lcDeleteRenderbuffers = (PFNGLDELETERENDERBUFFERSPROC)Context->getProcAddress("glDeleteRenderbuffers"); - lcGenRenderbuffers = (PFNGLGENRENDERBUFFERSPROC)Context->getProcAddress("glGenRenderbuffers"); - lcRenderbufferStorage = (PFNGLRENDERBUFFERSTORAGEPROC)Context->getProcAddress("glRenderbufferStorage"); - lcGetRenderbufferParameteriv = (PFNGLGETRENDERBUFFERPARAMETERIVPROC)Context->getProcAddress("glGetRenderbufferParameteriv"); - lcIsFramebuffer = (PFNGLISFRAMEBUFFERPROC)Context->getProcAddress("glIsFramebuffer"); - lcBindFramebuffer = (PFNGLBINDFRAMEBUFFERPROC)Context->getProcAddress("glBindFramebuffer"); - lcDeleteFramebuffers = (PFNGLDELETEFRAMEBUFFERSPROC)Context->getProcAddress("glDeleteFramebuffers"); - lcGenFramebuffers = (PFNGLGENFRAMEBUFFERSPROC)Context->getProcAddress("glGenFramebuffers"); - lcCheckFramebufferStatus = (PFNGLCHECKFRAMEBUFFERSTATUSPROC)Context->getProcAddress("glCheckFramebufferStatus"); - lcFramebufferTexture1D = (PFNGLFRAMEBUFFERTEXTURE1DPROC)Context->getProcAddress("glFramebufferTexture1D"); - lcFramebufferTexture2D = (PFNGLFRAMEBUFFERTEXTURE2DPROC)Context->getProcAddress("glFramebufferTexture2D"); - lcFramebufferTexture3D = (PFNGLFRAMEBUFFERTEXTURE3DPROC)Context->getProcAddress("glFramebufferTexture3D"); - lcFramebufferRenderbuffer = (PFNGLFRAMEBUFFERRENDERBUFFERPROC)Context->getProcAddress("glFramebufferRenderbuffer"); - lcGetFramebufferAttachmentParameteriv = (PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC)Context->getProcAddress("glGetFramebufferAttachmentParameteriv"); - lcGenerateMipmap = (PFNGLGENERATEMIPMAPPROC)Context->getProcAddress("glGenerateMipmap"); - lcBlitFramebuffer = (PFNGLBLITFRAMEBUFFERPROC)Context->getProcAddress("glBlitFramebuffer"); - lcRenderbufferStorageMultisample = (PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC)Context->getProcAddress("glRenderbufferStorageMultisample"); - lcFramebufferTextureLayer = (PFNGLFRAMEBUFFERTEXTURELAYERARBPROC)Context->getProcAddress("glFramebufferTextureLayer"); -#endif - gSupportsFramebufferObjectARB = true; - } - - if (lcIsGLExtensionSupported(Extensions, "GL_EXT_framebuffer_object")) - { -#ifdef LC_LOAD_GLEXTENSIONS - lcIsRenderbufferEXT = (PFNGLISRENDERBUFFEREXTPROC)Context->getProcAddress("glIsRenderbufferEXT"); - lcBindRenderbufferEXT = (PFNGLBINDRENDERBUFFEREXTPROC)Context->getProcAddress("glBindRenderbufferEXT"); - lcDeleteRenderbuffersEXT = (PFNGLDELETERENDERBUFFERSEXTPROC)Context->getProcAddress("glDeleteRenderbuffersEXT"); - lcGenRenderbuffersEXT = (PFNGLGENRENDERBUFFERSEXTPROC)Context->getProcAddress("glGenRenderbuffersEXT"); - lcRenderbufferStorageEXT = (PFNGLRENDERBUFFERSTORAGEEXTPROC)Context->getProcAddress("glRenderbufferStorageEXT"); - lcGetRenderbufferParameterivEXT = (PFNGLGETRENDERBUFFERPARAMETERIVEXTPROC)Context->getProcAddress("glGetRenderbufferParameterivEXT"); - lcIsFramebufferEXT = (PFNGLISFRAMEBUFFEREXTPROC)Context->getProcAddress("glIsFramebufferEXT"); - lcBindFramebufferEXT = (PFNGLBINDFRAMEBUFFEREXTPROC)Context->getProcAddress("glBindFramebufferEXT"); - lcDeleteFramebuffersEXT = (PFNGLDELETEFRAMEBUFFERSEXTPROC)Context->getProcAddress("glDeleteFramebuffersEXT"); - lcGenFramebuffersEXT = (PFNGLGENFRAMEBUFFERSEXTPROC)Context->getProcAddress("glGenFramebuffersEXT"); - lcCheckFramebufferStatusEXT = (PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC)Context->getProcAddress("glCheckFramebufferStatusEXT"); - lcFramebufferTexture1DEXT = (PFNGLFRAMEBUFFERTEXTURE1DEXTPROC)Context->getProcAddress("glFramebufferTexture1DEXT"); - lcFramebufferTexture2DEXT = (PFNGLFRAMEBUFFERTEXTURE2DEXTPROC)Context->getProcAddress("glFramebufferTexture2DEXT"); - lcFramebufferTexture3DEXT = (PFNGLFRAMEBUFFERTEXTURE3DEXTPROC)Context->getProcAddress("glFramebufferTexture3DEXT"); - lcFramebufferRenderbufferEXT = (PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC)Context->getProcAddress("glFramebufferRenderbufferEXT"); - lcGetFramebufferAttachmentParameterivEXT = (PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVEXTPROC)Context->getProcAddress("glGetFramebufferAttachmentParameterivEXT"); - lcGenerateMipmapEXT = (PFNGLGENERATEMIPMAPEXTPROC)Context->getProcAddress("glGenerateMipmapEXT"); -#endif - gSupportsFramebufferObjectEXT = true; - } - - const GLubyte* GLSLVersion = glGetString(GL_SHADING_LANGUAGE_VERSION); - int GLSLMajor = 0, GLSLMinor = 0; - - if (GLSLVersion) - sscanf((const char*)GLSLVersion, "%d.%d", &GLSLMajor, &GLSLMinor); - - if (VersionMajor >= 2 && (GLSLMajor > 1 || (GLSLMajor == 1 && GLSLMinor >= 10))) - { -#ifdef LC_LOAD_GLEXTENSIONS - lcAttachShader = (PFNGLATTACHSHADERPROC)Context->getProcAddress("glAttachShader"); - lcBindAttribLocation = (PFNGLBINDATTRIBLOCATIONPROC)Context->getProcAddress("glBindAttribLocation"); - lcCompileShader = (PFNGLCOMPILESHADERPROC)Context->getProcAddress("glCompileShader"); - lcCreateProgram = (PFNGLCREATEPROGRAMPROC)Context->getProcAddress("glCreateProgram"); - lcCreateShader = (PFNGLCREATESHADERPROC)Context->getProcAddress("glCreateShader"); - lcDeleteProgram = (PFNGLDELETEPROGRAMPROC)Context->getProcAddress("glDeleteProgram"); - lcDeleteShader = (PFNGLDELETESHADERPROC)Context->getProcAddress("glDeleteShader"); - lcDetachShader = (PFNGLDETACHSHADERPROC)Context->getProcAddress("glDetachShader"); - lcDisableVertexAttribArray = (PFNGLDISABLEVERTEXATTRIBARRAYPROC)Context->getProcAddress("glDisableVertexAttribArray"); - lcEnableVertexAttribArray = (PFNGLENABLEVERTEXATTRIBARRAYPROC)Context->getProcAddress("glEnableVertexAttribArray"); - lcGetActiveAttrib = (PFNGLGETACTIVEATTRIBPROC)Context->getProcAddress("glGetActiveAttrib"); - lcGetActiveUniform = (PFNGLGETACTIVEUNIFORMPROC)Context->getProcAddress("glGetActiveUniform"); - lcGetAttachedShaders = (PFNGLGETATTACHEDSHADERSPROC)Context->getProcAddress("glGetAttachedShaders"); - lcGetAttribLocation = (PFNGLGETATTRIBLOCATIONPROC)Context->getProcAddress("glGetAttribLocation"); - lcGetProgramiv = (PFNGLGETPROGRAMIVPROC)Context->getProcAddress("glGetProgramiv"); - lcGetProgramInfoLog = (PFNGLGETPROGRAMINFOLOGPROC)Context->getProcAddress("glGetProgramInfoLog"); - lcGetShaderiv = (PFNGLGETSHADERIVPROC)Context->getProcAddress("glGetShaderiv"); - lcGetShaderInfoLog = (PFNGLGETSHADERINFOLOGPROC)Context->getProcAddress("glGetShaderInfoLog"); - lcGetShaderSource = (PFNGLGETSHADERSOURCEPROC)Context->getProcAddress("glGetShaderSource"); - lcGetUniformLocation = (PFNGLGETUNIFORMLOCATIONPROC)Context->getProcAddress("glGetUniformLocation"); - lcGetUniformfv = (PFNGLGETUNIFORMFVPROC)Context->getProcAddress("glGetUniformfv"); - lcGetUniformiv = (PFNGLGETUNIFORMIVPROC)Context->getProcAddress("glGetUniformiv"); - lcGetVertexAttribdv = (PFNGLGETVERTEXATTRIBDVPROC)Context->getProcAddress("glGetVertexAttribdv"); - lcGetVertexAttribfv = (PFNGLGETVERTEXATTRIBFVPROC)Context->getProcAddress("glGetVertexAttribfv"); - lcGetVertexAttribiv = (PFNGLGETVERTEXATTRIBIVPROC)Context->getProcAddress("glGetVertexAttribiv"); - lcGetVertexAttribPointerv = (PFNGLGETVERTEXATTRIBPOINTERVPROC)Context->getProcAddress("glGetVertexAttribPointerv"); - lcIsProgram = (PFNGLISPROGRAMPROC)Context->getProcAddress("glIsProgram"); - lcIsShader = (PFNGLISSHADERPROC)Context->getProcAddress("glIsShader"); - lcLinkProgram = (PFNGLLINKPROGRAMPROC)Context->getProcAddress("glLinkProgram"); - lcShaderSource = (PFNGLSHADERSOURCEPROC)Context->getProcAddress("glShaderSource"); - lcUseProgram = (PFNGLUSEPROGRAMPROC)Context->getProcAddress("glUseProgram"); - lcUniform1f = (PFNGLUNIFORM1FPROC)Context->getProcAddress("glUniform1f"); - lcUniform2f = (PFNGLUNIFORM2FPROC)Context->getProcAddress("glUniform2f"); - lcUniform3f = (PFNGLUNIFORM3FPROC)Context->getProcAddress("glUniform3f"); - lcUniform4f = (PFNGLUNIFORM4FPROC)Context->getProcAddress("glUniform4f"); - lcUniform1i = (PFNGLUNIFORM1IPROC)Context->getProcAddress("glUniform1i"); - lcUniform2i = (PFNGLUNIFORM2IPROC)Context->getProcAddress("glUniform2i"); - lcUniform3i = (PFNGLUNIFORM3IPROC)Context->getProcAddress("glUniform3i"); - lcUniform4i = (PFNGLUNIFORM4IPROC)Context->getProcAddress("glUniform4i"); - lcUniform1fv = (PFNGLUNIFORM1FVPROC)Context->getProcAddress("glUniform1fv"); - lcUniform2fv = (PFNGLUNIFORM2FVPROC)Context->getProcAddress("glUniform2fv"); - lcUniform3fv = (PFNGLUNIFORM3FVPROC)Context->getProcAddress("glUniform3fv"); - lcUniform4fv = (PFNGLUNIFORM4FVPROC)Context->getProcAddress("glUniform4fv"); - lcUniform1iv = (PFNGLUNIFORM1IVPROC)Context->getProcAddress("glUniform1iv"); - lcUniform2iv = (PFNGLUNIFORM2IVPROC)Context->getProcAddress("glUniform2iv"); - lcUniform3iv = (PFNGLUNIFORM3IVPROC)Context->getProcAddress("glUniform3iv"); - lcUniform4iv = (PFNGLUNIFORM4IVPROC)Context->getProcAddress("glUniform4iv"); - lcUniformMatrix2fv = (PFNGLUNIFORMMATRIX2FVPROC)Context->getProcAddress("glUniformMatrix2fv"); - lcUniformMatrix3fv = (PFNGLUNIFORMMATRIX3FVPROC)Context->getProcAddress("glUniformMatrix3fv"); - lcUniformMatrix4fv = (PFNGLUNIFORMMATRIX4FVPROC)Context->getProcAddress("glUniformMatrix4fv"); - lcValidateProgram = (PFNGLVALIDATEPROGRAMPROC)Context->getProcAddress("glValidateProgram"); - lcVertexAttribPointer = (PFNGLVERTEXATTRIBPOINTERPROC)Context->getProcAddress("glVertexAttribPointer"); -#endif - gSupportsShaderObjects = true; - } -} +#include "lc_global.h" +#include "lc_glextensions.h" + +bool gSupportsShaderObjects; +bool gSupportsVertexBufferObject; +bool gSupportsFramebufferObjectARB; +bool gSupportsFramebufferObjectEXT; +bool gSupportsAnisotropic; +GLfloat gMaxAnisotropy; + +#ifdef LC_LOAD_GLEXTENSIONS + +PFNGLBINDBUFFERARBPROC lcBindBufferARB; +PFNGLDELETEBUFFERSARBPROC lcDeleteBuffersARB; +PFNGLGENBUFFERSARBPROC lcGenBuffersARB; +PFNGLISBUFFERARBPROC lcIsBufferARB; +PFNGLBUFFERDATAARBPROC lcBufferDataARB; +PFNGLBUFFERSUBDATAARBPROC lcBufferSubDataARB; +PFNGLGETBUFFERSUBDATAARBPROC lcGetBufferSubDataARB; +PFNGLMAPBUFFERARBPROC lcMapBufferARB; +PFNGLUNMAPBUFFERARBPROC lcUnmapBufferARB; +PFNGLGETBUFFERPARAMETERIVARBPROC lcGetBufferParameterivARB; +PFNGLGETBUFFERPOINTERVARBPROC lcGetBufferPointervARB; + +PFNGLISRENDERBUFFERPROC lcIsRenderbuffer; +PFNGLBINDRENDERBUFFERPROC lcBindRenderbuffer; +PFNGLDELETERENDERBUFFERSPROC lcDeleteRenderbuffers; +PFNGLGENRENDERBUFFERSPROC lcGenRenderbuffers; +PFNGLRENDERBUFFERSTORAGEPROC lcRenderbufferStorage; +PFNGLGETRENDERBUFFERPARAMETERIVPROC lcGetRenderbufferParameteriv; +PFNGLISFRAMEBUFFERPROC lcIsFramebuffer; +PFNGLBINDFRAMEBUFFERPROC lcBindFramebuffer; +PFNGLDELETEFRAMEBUFFERSPROC lcDeleteFramebuffers; +PFNGLGENFRAMEBUFFERSPROC lcGenFramebuffers; +PFNGLCHECKFRAMEBUFFERSTATUSPROC lcCheckFramebufferStatus; +PFNGLFRAMEBUFFERTEXTURE1DPROC lcFramebufferTexture1D; +PFNGLFRAMEBUFFERTEXTURE2DPROC lcFramebufferTexture2D; +PFNGLFRAMEBUFFERTEXTURE3DPROC lcFramebufferTexture3D; +PFNGLFRAMEBUFFERRENDERBUFFERPROC lcFramebufferRenderbuffer; +PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC lcGetFramebufferAttachmentParameteriv; +PFNGLGENERATEMIPMAPPROC lcGenerateMipmap; +PFNGLBLITFRAMEBUFFERPROC lcBlitFramebuffer; +PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC lcRenderbufferStorageMultisample; +PFNGLFRAMEBUFFERTEXTURELAYERPROC lcFramebufferTextureLayer; + +PFNGLISRENDERBUFFEREXTPROC lcIsRenderbufferEXT; +PFNGLBINDRENDERBUFFEREXTPROC lcBindRenderbufferEXT; +PFNGLDELETERENDERBUFFERSEXTPROC lcDeleteRenderbuffersEXT; +PFNGLGENRENDERBUFFERSEXTPROC lcGenRenderbuffersEXT; +PFNGLRENDERBUFFERSTORAGEEXTPROC lcRenderbufferStorageEXT; +PFNGLGETRENDERBUFFERPARAMETERIVEXTPROC lcGetRenderbufferParameterivEXT; +PFNGLISFRAMEBUFFEREXTPROC lcIsFramebufferEXT; +PFNGLBINDFRAMEBUFFEREXTPROC lcBindFramebufferEXT; +PFNGLDELETEFRAMEBUFFERSEXTPROC lcDeleteFramebuffersEXT; +PFNGLGENFRAMEBUFFERSEXTPROC lcGenFramebuffersEXT; +PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC lcCheckFramebufferStatusEXT; +PFNGLFRAMEBUFFERTEXTURE1DEXTPROC lcFramebufferTexture1DEXT; +PFNGLFRAMEBUFFERTEXTURE2DEXTPROC lcFramebufferTexture2DEXT; +PFNGLFRAMEBUFFERTEXTURE3DEXTPROC lcFramebufferTexture3DEXT; +PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC lcFramebufferRenderbufferEXT; +PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVEXTPROC lcGetFramebufferAttachmentParameterivEXT; +PFNGLGENERATEMIPMAPEXTPROC lcGenerateMipmapEXT; + +PFNGLATTACHSHADERPROC lcAttachShader; +PFNGLBINDATTRIBLOCATIONPROC lcBindAttribLocation; +PFNGLCOMPILESHADERPROC lcCompileShader; +PFNGLCREATEPROGRAMPROC lcCreateProgram; +PFNGLCREATESHADERPROC lcCreateShader; +PFNGLDELETEPROGRAMPROC lcDeleteProgram; +PFNGLDELETESHADERPROC lcDeleteShader; +PFNGLDETACHSHADERPROC lcDetachShader; +PFNGLDISABLEVERTEXATTRIBARRAYPROC lcDisableVertexAttribArray; +PFNGLENABLEVERTEXATTRIBARRAYPROC lcEnableVertexAttribArray; +PFNGLGETACTIVEATTRIBPROC lcGetActiveAttrib; +PFNGLGETACTIVEUNIFORMPROC lcGetActiveUniform; +PFNGLGETATTACHEDSHADERSPROC lcGetAttachedShaders; +PFNGLGETATTRIBLOCATIONPROC lcGetAttribLocation; +PFNGLGETPROGRAMIVPROC lcGetProgramiv; +PFNGLGETPROGRAMINFOLOGPROC lcGetProgramInfoLog; +PFNGLGETSHADERIVPROC lcGetShaderiv; +PFNGLGETSHADERINFOLOGPROC lcGetShaderInfoLog; +PFNGLGETSHADERSOURCEPROC lcGetShaderSource; +PFNGLGETUNIFORMLOCATIONPROC lcGetUniformLocation; +PFNGLGETUNIFORMFVPROC lcGetUniformfv; +PFNGLGETUNIFORMIVPROC lcGetUniformiv; +PFNGLGETVERTEXATTRIBDVPROC lcGetVertexAttribdv; +PFNGLGETVERTEXATTRIBFVPROC lcGetVertexAttribfv; +PFNGLGETVERTEXATTRIBIVPROC lcGetVertexAttribiv; +PFNGLGETVERTEXATTRIBPOINTERVPROC lcGetVertexAttribPointerv; +PFNGLISPROGRAMPROC lcIsProgram; +PFNGLISSHADERPROC lcIsShader; +PFNGLLINKPROGRAMPROC lcLinkProgram; +PFNGLSHADERSOURCEPROC lcShaderSource; +PFNGLUSEPROGRAMPROC lcUseProgram; +PFNGLUNIFORM1FPROC lcUniform1f; +PFNGLUNIFORM2FPROC lcUniform2f; +PFNGLUNIFORM3FPROC lcUniform3f; +PFNGLUNIFORM4FPROC lcUniform4f; +PFNGLUNIFORM1IPROC lcUniform1i; +PFNGLUNIFORM2IPROC lcUniform2i; +PFNGLUNIFORM3IPROC lcUniform3i; +PFNGLUNIFORM4IPROC lcUniform4i; +PFNGLUNIFORM1FVPROC lcUniform1fv; +PFNGLUNIFORM2FVPROC lcUniform2fv; +PFNGLUNIFORM3FVPROC lcUniform3fv; +PFNGLUNIFORM4FVPROC lcUniform4fv; +PFNGLUNIFORM1IVPROC lcUniform1iv; +PFNGLUNIFORM2IVPROC lcUniform2iv; +PFNGLUNIFORM3IVPROC lcUniform3iv; +PFNGLUNIFORM4IVPROC lcUniform4iv; +PFNGLUNIFORMMATRIX2FVPROC lcUniformMatrix2fv; +PFNGLUNIFORMMATRIX3FVPROC lcUniformMatrix3fv; +PFNGLUNIFORMMATRIX4FVPROC lcUniformMatrix4fv; +PFNGLVALIDATEPROGRAMPROC lcValidateProgram; +PFNGLVERTEXATTRIBPOINTERPROC lcVertexAttribPointer; + +#endif + +static bool lcIsGLExtensionSupported(const GLubyte* Extensions, const char* Name) +{ + const GLubyte* Start; + GLubyte* Where; + GLubyte* Terminator; + + Where = (GLubyte*)strchr(Name, ' '); + if (Where || *Name == '\0') + return false; + + if (!Extensions) + return false; + + for (Start = Extensions; ;) + { + Where = (GLubyte*)strstr((const char*)Start, Name); + if (!Where) + break; + + Terminator = Where + strlen(Name); + if (Where == Start || *(Where - 1) == ' ') + if (*Terminator == ' ' || *Terminator == '\0') + return true; + + Start = Terminator; + } + + return false; +} + +#if !defined(QT_NO_DEBUG) && defined(GL_ARB_debug_output) + +static void APIENTRY lcGLDebugCallback(GLenum Source, GLenum Type, GLuint Id, GLenum Severity, GLsizei Length, const GLchar* Message, GLvoid* UserParam) +{ + Q_UNUSED(Source); + Q_UNUSED(Type); + Q_UNUSED(Id); + Q_UNUSED(Severity); + Q_UNUSED(Length); + Q_UNUSED(UserParam); + + qDebug() << Message; +} + +#endif + +void lcInitializeGLExtensions(const QGLContext* Context) +{ + const GLubyte* Extensions = glGetString(GL_EXTENSIONS); + const GLubyte* Version = glGetString(GL_VERSION); + int VersionMajor = 0, VersionMinor = 0; + + if (Version) + sscanf((const char*)Version, "%d.%d", &VersionMajor, &VersionMinor); + +#if !defined(QT_NO_DEBUG) && defined(GL_ARB_debug_output) + if (lcIsGLExtensionSupported(Extensions, "GL_KHR_debug")) + { + PFNGLDEBUGMESSAGECALLBACKARBPROC DebugMessageCallback = (PFNGLDEBUGMESSAGECALLBACKARBPROC)Context->getProcAddress("glDebugMessageCallback"); + +#ifndef GL_DEBUG_OUTPUT +#define GL_DEBUG_OUTPUT 0x92E0 +#endif + + if (DebugMessageCallback) + { + DebugMessageCallback((GLDEBUGPROCARB)&lcGLDebugCallback, NULL); + glEnable(GL_DEBUG_OUTPUT); + glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB); + } + } +#endif + + if (lcIsGLExtensionSupported(Extensions, "GL_EXT_texture_filter_anisotropic")) + { + glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &gMaxAnisotropy); + + gSupportsAnisotropic = true; + } + + // todo: check gl version and use core functions instead + if (lcIsGLExtensionSupported(Extensions, "GL_ARB_vertex_buffer_object")) + { +#ifdef LC_LOAD_GLEXTENSIONS + lcBindBufferARB = (PFNGLBINDBUFFERARBPROC)Context->getProcAddress("glBindBufferARB"); + lcDeleteBuffersARB = (PFNGLDELETEBUFFERSARBPROC)Context->getProcAddress("glDeleteBuffersARB"); + lcGenBuffersARB = (PFNGLGENBUFFERSARBPROC)Context->getProcAddress("glGenBuffersARB"); + lcIsBufferARB = (PFNGLISBUFFERARBPROC)Context->getProcAddress("glIsBufferARB"); + lcBufferDataARB = (PFNGLBUFFERDATAARBPROC)Context->getProcAddress("glBufferDataARB"); + lcBufferSubDataARB = (PFNGLBUFFERSUBDATAARBPROC)Context->getProcAddress("glBufferSubDataARB"); + lcGetBufferSubDataARB = (PFNGLGETBUFFERSUBDATAARBPROC)Context->getProcAddress("glGetBufferSubDataARB"); + lcMapBufferARB = (PFNGLMAPBUFFERARBPROC)Context->getProcAddress("glMapBufferARB"); + lcUnmapBufferARB = (PFNGLUNMAPBUFFERARBPROC)Context->getProcAddress("glUnmapBufferARB"); + lcGetBufferParameterivARB = (PFNGLGETBUFFERPARAMETERIVARBPROC)Context->getProcAddress("glGetBufferParameterivARB"); + lcGetBufferPointervARB = (PFNGLGETBUFFERPOINTERVARBPROC)Context->getProcAddress("glGetBufferPointervARB"); +#endif + gSupportsVertexBufferObject = true; + } + + // todo: check gl version + if (lcIsGLExtensionSupported(Extensions, "GL_ARB_framebuffer_object")) + { +#ifdef LC_LOAD_GLEXTENSIONS + lcIsRenderbuffer = (PFNGLISRENDERBUFFERPROC)Context->getProcAddress("glIsRenderbuffer"); + lcBindRenderbuffer = (PFNGLBINDRENDERBUFFERPROC)Context->getProcAddress("glBindRenderbuffer"); + lcDeleteRenderbuffers = (PFNGLDELETERENDERBUFFERSPROC)Context->getProcAddress("glDeleteRenderbuffers"); + lcGenRenderbuffers = (PFNGLGENRENDERBUFFERSPROC)Context->getProcAddress("glGenRenderbuffers"); + lcRenderbufferStorage = (PFNGLRENDERBUFFERSTORAGEPROC)Context->getProcAddress("glRenderbufferStorage"); + lcGetRenderbufferParameteriv = (PFNGLGETRENDERBUFFERPARAMETERIVPROC)Context->getProcAddress("glGetRenderbufferParameteriv"); + lcIsFramebuffer = (PFNGLISFRAMEBUFFERPROC)Context->getProcAddress("glIsFramebuffer"); + lcBindFramebuffer = (PFNGLBINDFRAMEBUFFERPROC)Context->getProcAddress("glBindFramebuffer"); + lcDeleteFramebuffers = (PFNGLDELETEFRAMEBUFFERSPROC)Context->getProcAddress("glDeleteFramebuffers"); + lcGenFramebuffers = (PFNGLGENFRAMEBUFFERSPROC)Context->getProcAddress("glGenFramebuffers"); + lcCheckFramebufferStatus = (PFNGLCHECKFRAMEBUFFERSTATUSPROC)Context->getProcAddress("glCheckFramebufferStatus"); + lcFramebufferTexture1D = (PFNGLFRAMEBUFFERTEXTURE1DPROC)Context->getProcAddress("glFramebufferTexture1D"); + lcFramebufferTexture2D = (PFNGLFRAMEBUFFERTEXTURE2DPROC)Context->getProcAddress("glFramebufferTexture2D"); + lcFramebufferTexture3D = (PFNGLFRAMEBUFFERTEXTURE3DPROC)Context->getProcAddress("glFramebufferTexture3D"); + lcFramebufferRenderbuffer = (PFNGLFRAMEBUFFERRENDERBUFFERPROC)Context->getProcAddress("glFramebufferRenderbuffer"); + lcGetFramebufferAttachmentParameteriv = (PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC)Context->getProcAddress("glGetFramebufferAttachmentParameteriv"); + lcGenerateMipmap = (PFNGLGENERATEMIPMAPPROC)Context->getProcAddress("glGenerateMipmap"); + lcBlitFramebuffer = (PFNGLBLITFRAMEBUFFERPROC)Context->getProcAddress("glBlitFramebuffer"); + lcRenderbufferStorageMultisample = (PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC)Context->getProcAddress("glRenderbufferStorageMultisample"); + lcFramebufferTextureLayer = (PFNGLFRAMEBUFFERTEXTURELAYERARBPROC)Context->getProcAddress("glFramebufferTextureLayer"); +#endif + gSupportsFramebufferObjectARB = true; + } + + if (lcIsGLExtensionSupported(Extensions, "GL_EXT_framebuffer_object")) + { +#ifdef LC_LOAD_GLEXTENSIONS + lcIsRenderbufferEXT = (PFNGLISRENDERBUFFEREXTPROC)Context->getProcAddress("glIsRenderbufferEXT"); + lcBindRenderbufferEXT = (PFNGLBINDRENDERBUFFEREXTPROC)Context->getProcAddress("glBindRenderbufferEXT"); + lcDeleteRenderbuffersEXT = (PFNGLDELETERENDERBUFFERSEXTPROC)Context->getProcAddress("glDeleteRenderbuffersEXT"); + lcGenRenderbuffersEXT = (PFNGLGENRENDERBUFFERSEXTPROC)Context->getProcAddress("glGenRenderbuffersEXT"); + lcRenderbufferStorageEXT = (PFNGLRENDERBUFFERSTORAGEEXTPROC)Context->getProcAddress("glRenderbufferStorageEXT"); + lcGetRenderbufferParameterivEXT = (PFNGLGETRENDERBUFFERPARAMETERIVEXTPROC)Context->getProcAddress("glGetRenderbufferParameterivEXT"); + lcIsFramebufferEXT = (PFNGLISFRAMEBUFFEREXTPROC)Context->getProcAddress("glIsFramebufferEXT"); + lcBindFramebufferEXT = (PFNGLBINDFRAMEBUFFEREXTPROC)Context->getProcAddress("glBindFramebufferEXT"); + lcDeleteFramebuffersEXT = (PFNGLDELETEFRAMEBUFFERSEXTPROC)Context->getProcAddress("glDeleteFramebuffersEXT"); + lcGenFramebuffersEXT = (PFNGLGENFRAMEBUFFERSEXTPROC)Context->getProcAddress("glGenFramebuffersEXT"); + lcCheckFramebufferStatusEXT = (PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC)Context->getProcAddress("glCheckFramebufferStatusEXT"); + lcFramebufferTexture1DEXT = (PFNGLFRAMEBUFFERTEXTURE1DEXTPROC)Context->getProcAddress("glFramebufferTexture1DEXT"); + lcFramebufferTexture2DEXT = (PFNGLFRAMEBUFFERTEXTURE2DEXTPROC)Context->getProcAddress("glFramebufferTexture2DEXT"); + lcFramebufferTexture3DEXT = (PFNGLFRAMEBUFFERTEXTURE3DEXTPROC)Context->getProcAddress("glFramebufferTexture3DEXT"); + lcFramebufferRenderbufferEXT = (PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC)Context->getProcAddress("glFramebufferRenderbufferEXT"); + lcGetFramebufferAttachmentParameterivEXT = (PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVEXTPROC)Context->getProcAddress("glGetFramebufferAttachmentParameterivEXT"); + lcGenerateMipmapEXT = (PFNGLGENERATEMIPMAPEXTPROC)Context->getProcAddress("glGenerateMipmapEXT"); +#endif + gSupportsFramebufferObjectEXT = true; + } + + const GLubyte* GLSLVersion = glGetString(GL_SHADING_LANGUAGE_VERSION); + int GLSLMajor = 0, GLSLMinor = 0; + + if (GLSLVersion) + sscanf((const char*)GLSLVersion, "%d.%d", &GLSLMajor, &GLSLMinor); + + if (VersionMajor >= 2 && (GLSLMajor > 1 || (GLSLMajor == 1 && GLSLMinor >= 10))) + { +#ifdef LC_LOAD_GLEXTENSIONS + lcAttachShader = (PFNGLATTACHSHADERPROC)Context->getProcAddress("glAttachShader"); + lcBindAttribLocation = (PFNGLBINDATTRIBLOCATIONPROC)Context->getProcAddress("glBindAttribLocation"); + lcCompileShader = (PFNGLCOMPILESHADERPROC)Context->getProcAddress("glCompileShader"); + lcCreateProgram = (PFNGLCREATEPROGRAMPROC)Context->getProcAddress("glCreateProgram"); + lcCreateShader = (PFNGLCREATESHADERPROC)Context->getProcAddress("glCreateShader"); + lcDeleteProgram = (PFNGLDELETEPROGRAMPROC)Context->getProcAddress("glDeleteProgram"); + lcDeleteShader = (PFNGLDELETESHADERPROC)Context->getProcAddress("glDeleteShader"); + lcDetachShader = (PFNGLDETACHSHADERPROC)Context->getProcAddress("glDetachShader"); + lcDisableVertexAttribArray = (PFNGLDISABLEVERTEXATTRIBARRAYPROC)Context->getProcAddress("glDisableVertexAttribArray"); + lcEnableVertexAttribArray = (PFNGLENABLEVERTEXATTRIBARRAYPROC)Context->getProcAddress("glEnableVertexAttribArray"); + lcGetActiveAttrib = (PFNGLGETACTIVEATTRIBPROC)Context->getProcAddress("glGetActiveAttrib"); + lcGetActiveUniform = (PFNGLGETACTIVEUNIFORMPROC)Context->getProcAddress("glGetActiveUniform"); + lcGetAttachedShaders = (PFNGLGETATTACHEDSHADERSPROC)Context->getProcAddress("glGetAttachedShaders"); + lcGetAttribLocation = (PFNGLGETATTRIBLOCATIONPROC)Context->getProcAddress("glGetAttribLocation"); + lcGetProgramiv = (PFNGLGETPROGRAMIVPROC)Context->getProcAddress("glGetProgramiv"); + lcGetProgramInfoLog = (PFNGLGETPROGRAMINFOLOGPROC)Context->getProcAddress("glGetProgramInfoLog"); + lcGetShaderiv = (PFNGLGETSHADERIVPROC)Context->getProcAddress("glGetShaderiv"); + lcGetShaderInfoLog = (PFNGLGETSHADERINFOLOGPROC)Context->getProcAddress("glGetShaderInfoLog"); + lcGetShaderSource = (PFNGLGETSHADERSOURCEPROC)Context->getProcAddress("glGetShaderSource"); + lcGetUniformLocation = (PFNGLGETUNIFORMLOCATIONPROC)Context->getProcAddress("glGetUniformLocation"); + lcGetUniformfv = (PFNGLGETUNIFORMFVPROC)Context->getProcAddress("glGetUniformfv"); + lcGetUniformiv = (PFNGLGETUNIFORMIVPROC)Context->getProcAddress("glGetUniformiv"); + lcGetVertexAttribdv = (PFNGLGETVERTEXATTRIBDVPROC)Context->getProcAddress("glGetVertexAttribdv"); + lcGetVertexAttribfv = (PFNGLGETVERTEXATTRIBFVPROC)Context->getProcAddress("glGetVertexAttribfv"); + lcGetVertexAttribiv = (PFNGLGETVERTEXATTRIBIVPROC)Context->getProcAddress("glGetVertexAttribiv"); + lcGetVertexAttribPointerv = (PFNGLGETVERTEXATTRIBPOINTERVPROC)Context->getProcAddress("glGetVertexAttribPointerv"); + lcIsProgram = (PFNGLISPROGRAMPROC)Context->getProcAddress("glIsProgram"); + lcIsShader = (PFNGLISSHADERPROC)Context->getProcAddress("glIsShader"); + lcLinkProgram = (PFNGLLINKPROGRAMPROC)Context->getProcAddress("glLinkProgram"); + lcShaderSource = (PFNGLSHADERSOURCEPROC)Context->getProcAddress("glShaderSource"); + lcUseProgram = (PFNGLUSEPROGRAMPROC)Context->getProcAddress("glUseProgram"); + lcUniform1f = (PFNGLUNIFORM1FPROC)Context->getProcAddress("glUniform1f"); + lcUniform2f = (PFNGLUNIFORM2FPROC)Context->getProcAddress("glUniform2f"); + lcUniform3f = (PFNGLUNIFORM3FPROC)Context->getProcAddress("glUniform3f"); + lcUniform4f = (PFNGLUNIFORM4FPROC)Context->getProcAddress("glUniform4f"); + lcUniform1i = (PFNGLUNIFORM1IPROC)Context->getProcAddress("glUniform1i"); + lcUniform2i = (PFNGLUNIFORM2IPROC)Context->getProcAddress("glUniform2i"); + lcUniform3i = (PFNGLUNIFORM3IPROC)Context->getProcAddress("glUniform3i"); + lcUniform4i = (PFNGLUNIFORM4IPROC)Context->getProcAddress("glUniform4i"); + lcUniform1fv = (PFNGLUNIFORM1FVPROC)Context->getProcAddress("glUniform1fv"); + lcUniform2fv = (PFNGLUNIFORM2FVPROC)Context->getProcAddress("glUniform2fv"); + lcUniform3fv = (PFNGLUNIFORM3FVPROC)Context->getProcAddress("glUniform3fv"); + lcUniform4fv = (PFNGLUNIFORM4FVPROC)Context->getProcAddress("glUniform4fv"); + lcUniform1iv = (PFNGLUNIFORM1IVPROC)Context->getProcAddress("glUniform1iv"); + lcUniform2iv = (PFNGLUNIFORM2IVPROC)Context->getProcAddress("glUniform2iv"); + lcUniform3iv = (PFNGLUNIFORM3IVPROC)Context->getProcAddress("glUniform3iv"); + lcUniform4iv = (PFNGLUNIFORM4IVPROC)Context->getProcAddress("glUniform4iv"); + lcUniformMatrix2fv = (PFNGLUNIFORMMATRIX2FVPROC)Context->getProcAddress("glUniformMatrix2fv"); + lcUniformMatrix3fv = (PFNGLUNIFORMMATRIX3FVPROC)Context->getProcAddress("glUniformMatrix3fv"); + lcUniformMatrix4fv = (PFNGLUNIFORMMATRIX4FVPROC)Context->getProcAddress("glUniformMatrix4fv"); + lcValidateProgram = (PFNGLVALIDATEPROGRAMPROC)Context->getProcAddress("glValidateProgram"); + lcVertexAttribPointer = (PFNGLVERTEXATTRIBPOINTERPROC)Context->getProcAddress("glVertexAttribPointer"); +#endif + gSupportsShaderObjects = true; + } +} diff --git a/common/lc_glextensions.h b/common/lc_glextensions.h index 3a47502b..e0533edf 100644 --- a/common/lc_glextensions.h +++ b/common/lc_glextensions.h @@ -1,229 +1,229 @@ -#ifndef _LC_GLEXTENSIONS_H_ -#define _LC_GLEXTENSIONS_H_ - -void lcInitializeGLExtensions(const QGLContext* Context); - -extern bool gSupportsShaderObjects; -extern bool gSupportsVertexBufferObject; -extern bool gSupportsFramebufferObjectARB; -extern bool gSupportsFramebufferObjectEXT; -extern bool gSupportsAnisotropic; -extern GLfloat gMaxAnisotropy; - -#ifndef Q_OS_MAC -#define LC_LOAD_GLEXTENSIONS -#endif - -#ifdef LC_LOAD_GLEXTENSIONS - -extern PFNGLBINDBUFFERARBPROC lcBindBufferARB; -extern PFNGLDELETEBUFFERSARBPROC lcDeleteBuffersARB; -extern PFNGLGENBUFFERSARBPROC lcGenBuffersARB; -extern PFNGLISBUFFERARBPROC lcIsBufferARB; -extern PFNGLBUFFERDATAARBPROC lcBufferDataARB; -extern PFNGLBUFFERSUBDATAARBPROC lcBufferSubDataARB; -extern PFNGLGETBUFFERSUBDATAARBPROC lcGetBufferSubDataARB; -extern PFNGLMAPBUFFERARBPROC lcMapBufferARB; -extern PFNGLUNMAPBUFFERARBPROC lcUnmapBufferARB; -extern PFNGLGETBUFFERPARAMETERIVARBPROC lcGetBufferParameterivARB; -extern PFNGLGETBUFFERPOINTERVARBPROC lcGetBufferPointervARB; - -extern PFNGLISRENDERBUFFERPROC lcIsRenderbuffer; -extern PFNGLBINDRENDERBUFFERPROC lcBindRenderbuffer; -extern PFNGLDELETERENDERBUFFERSPROC lcDeleteRenderbuffers; -extern PFNGLGENRENDERBUFFERSPROC lcGenRenderbuffers; -extern PFNGLRENDERBUFFERSTORAGEPROC lcRenderbufferStorage; -extern PFNGLGETRENDERBUFFERPARAMETERIVPROC lcGetRenderbufferParameteriv; -extern PFNGLISFRAMEBUFFERPROC lcIsFramebuffer; -extern PFNGLBINDFRAMEBUFFERPROC lcBindFramebuffer; -extern PFNGLDELETEFRAMEBUFFERSPROC lcDeleteFramebuffers; -extern PFNGLGENFRAMEBUFFERSPROC lcGenFramebuffers; -extern PFNGLCHECKFRAMEBUFFERSTATUSPROC lcCheckFramebufferStatus; -extern PFNGLFRAMEBUFFERTEXTURE1DPROC lcFramebufferTexture1D; -extern PFNGLFRAMEBUFFERTEXTURE2DPROC lcFramebufferTexture2D; -extern PFNGLFRAMEBUFFERTEXTURE3DPROC lcFramebufferTexture3D; -extern PFNGLFRAMEBUFFERRENDERBUFFERPROC lcFramebufferRenderbuffer; -extern PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC lcGetFramebufferAttachmentParameteriv; -extern PFNGLGENERATEMIPMAPPROC lcGenerateMipmap; -extern PFNGLBLITFRAMEBUFFERPROC lcBlitFramebuffer; -extern PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC lcRenderbufferStorageMultisample; -extern PFNGLFRAMEBUFFERTEXTURELAYERPROC lcFramebufferTextureLayer; - -extern PFNGLISRENDERBUFFEREXTPROC lcIsRenderbufferEXT; -extern PFNGLBINDRENDERBUFFEREXTPROC lcBindRenderbufferEXT; -extern PFNGLDELETERENDERBUFFERSEXTPROC lcDeleteRenderbuffersEXT; -extern PFNGLGENRENDERBUFFERSEXTPROC lcGenRenderbuffersEXT; -extern PFNGLRENDERBUFFERSTORAGEEXTPROC lcRenderbufferStorageEXT; -extern PFNGLGETRENDERBUFFERPARAMETERIVEXTPROC lcGetRenderbufferParameterivEXT; -extern PFNGLISFRAMEBUFFEREXTPROC lcIsFramebufferEXT; -extern PFNGLBINDFRAMEBUFFEREXTPROC lcBindFramebufferEXT; -extern PFNGLDELETEFRAMEBUFFERSEXTPROC lcDeleteFramebuffersEXT; -extern PFNGLGENFRAMEBUFFERSEXTPROC lcGenFramebuffersEXT; -extern PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC lcCheckFramebufferStatusEXT; -extern PFNGLFRAMEBUFFERTEXTURE1DEXTPROC lcFramebufferTexture1DEXT; -extern PFNGLFRAMEBUFFERTEXTURE2DEXTPROC lcFramebufferTexture2DEXT; -extern PFNGLFRAMEBUFFERTEXTURE3DEXTPROC lcFramebufferTexture3DEXT; -extern PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC lcFramebufferRenderbufferEXT; -extern PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVEXTPROC lcGetFramebufferAttachmentParameterivEXT; -extern PFNGLGENERATEMIPMAPEXTPROC lcGenerateMipmapEXT; - -extern PFNGLATTACHSHADERPROC lcAttachShader; -extern PFNGLBINDATTRIBLOCATIONPROC lcBindAttribLocation; -extern PFNGLCOMPILESHADERPROC lcCompileShader; -extern PFNGLCREATEPROGRAMPROC lcCreateProgram; -extern PFNGLCREATESHADERPROC lcCreateShader; -extern PFNGLDELETEPROGRAMPROC lcDeleteProgram; -extern PFNGLDELETESHADERPROC lcDeleteShader; -extern PFNGLDETACHSHADERPROC lcDetachShader; -extern PFNGLDISABLEVERTEXATTRIBARRAYPROC lcDisableVertexAttribArray; -extern PFNGLENABLEVERTEXATTRIBARRAYPROC lcEnableVertexAttribArray; -extern PFNGLGETACTIVEATTRIBPROC lcGetActiveAttrib; -extern PFNGLGETACTIVEUNIFORMPROC lcGetActiveUniform; -extern PFNGLGETATTACHEDSHADERSPROC lcGetAttachedShaders; -extern PFNGLGETATTRIBLOCATIONPROC lcGetAttribLocation; -extern PFNGLGETPROGRAMIVPROC lcGetProgramiv; -extern PFNGLGETPROGRAMINFOLOGPROC lcGetProgramInfoLog; -extern PFNGLGETSHADERIVPROC lcGetShaderiv; -extern PFNGLGETSHADERINFOLOGPROC lcGetShaderInfoLog; -extern PFNGLGETSHADERSOURCEPROC lcGetShaderSource; -extern PFNGLGETUNIFORMLOCATIONPROC lcGetUniformLocation; -extern PFNGLGETUNIFORMFVPROC lcGetUniformfv; -extern PFNGLGETUNIFORMIVPROC lcGetUniformiv; -extern PFNGLGETVERTEXATTRIBDVPROC lcGetVertexAttribdv; -extern PFNGLGETVERTEXATTRIBFVPROC lcGetVertexAttribfv; -extern PFNGLGETVERTEXATTRIBIVPROC lcGetVertexAttribiv; -extern PFNGLGETVERTEXATTRIBPOINTERVPROC lcGetVertexAttribPointerv; -extern PFNGLISPROGRAMPROC lcIsProgram; -extern PFNGLISSHADERPROC lcIsShader; -extern PFNGLLINKPROGRAMPROC lcLinkProgram; -extern PFNGLSHADERSOURCEPROC lcShaderSource; -extern PFNGLUSEPROGRAMPROC lcUseProgram; -extern PFNGLUNIFORM1FPROC lcUniform1f; -extern PFNGLUNIFORM2FPROC lcUniform2f; -extern PFNGLUNIFORM3FPROC lcUniform3f; -extern PFNGLUNIFORM4FPROC lcUniform4f; -extern PFNGLUNIFORM1IPROC lcUniform1i; -extern PFNGLUNIFORM2IPROC lcUniform2i; -extern PFNGLUNIFORM3IPROC lcUniform3i; -extern PFNGLUNIFORM4IPROC lcUniform4i; -extern PFNGLUNIFORM1FVPROC lcUniform1fv; -extern PFNGLUNIFORM2FVPROC lcUniform2fv; -extern PFNGLUNIFORM3FVPROC lcUniform3fv; -extern PFNGLUNIFORM4FVPROC lcUniform4fv; -extern PFNGLUNIFORM1IVPROC lcUniform1iv; -extern PFNGLUNIFORM2IVPROC lcUniform2iv; -extern PFNGLUNIFORM3IVPROC lcUniform3iv; -extern PFNGLUNIFORM4IVPROC lcUniform4iv; -extern PFNGLUNIFORMMATRIX2FVPROC lcUniformMatrix2fv; -extern PFNGLUNIFORMMATRIX3FVPROC lcUniformMatrix3fv; -extern PFNGLUNIFORMMATRIX4FVPROC lcUniformMatrix4fv; -extern PFNGLVALIDATEPROGRAMPROC lcValidateProgram; -extern PFNGLVERTEXATTRIBPOINTERPROC lcVertexAttribPointer; - -#define glBindBuffer lcBindBufferARB -#define glDeleteBuffers lcDeleteBuffersARB -#define glGenBuffers lcGenBuffersARB -#define glIsBuffer lcIsBufferARB -#define glBufferData lcBufferDataARB -#define glBufferSubData lcBufferSubDataARB -#define glGetBufferSubData lcGetBufferSubDataARB -#define glMapBuffer lcMapBufferARB -#define glUnmapBuffer lcUnmapBufferARB -#define glGetBufferParameteriv lcGetBufferParameterivARB -#define glGetBufferPointerv lcGetBufferPointervARB - -#define glIsRenderbuffer lcIsRenderbuffer -#define glBindRenderbuffer lcBindRenderbuffer -#define glDeleteRenderbuffers lcDeleteRenderbuffers -#define glGenRenderbuffers lcGenRenderbuffers -#define glRenderbufferStorage lcRenderbufferStorage -#define glGetRenderbufferParameteriv lcGetRenderbufferParameteriv -#define glIsFramebuffer lcIsFramebuffer -#define glBindFramebuffer lcBindFramebuffer -#define glDeleteFramebuffers lcDeleteFramebuffers -#define glGenFramebuffers lcGenFramebuffers -#define glCheckFramebufferStatus lcCheckFramebufferStatus -#define glFramebufferTexture1D lcFramebufferTexture1D -#define glFramebufferTexture2D lcFramebufferTexture2D -#define glFramebufferTexture3D lcFramebufferTexture3D -#define glFramebufferRenderbuffer lcFramebufferRenderbuffer -#define glGetFramebufferAttachmentParameteriv lcGetFramebufferAttachmentParameteriv -#define glGenerateMipmap lcGenerateMipmap -#define glBlitFramebuffer lcBlitFramebuffer -#define glRenderbufferStorageMultisample lcRenderbufferStorageMultisample -#define glFramebufferTextureLayer lcFramebufferTextureLayer - -#define glIsRenderbufferEXT lcIsRenderbufferEXT -#define glBindRenderbufferEXT lcBindRenderbufferEXT -#define glDeleteRenderbuffersEXT lcDeleteRenderbuffersEXT -#define glGenRenderbuffersEXT lcGenRenderbuffersEXT -#define glRenderbufferStorageEXT lcRenderbufferStorageEXT -#define glGetRenderbufferParameterivEXT lcGetRenderbufferParameterivEXT -#define glIsFramebufferEXT lcIsFramebufferEXT -#define glBindFramebufferEXT lcBindFramebufferEXT -#define glDeleteFramebuffersEXT lcDeleteFramebuffersEXT -#define glGenFramebuffersEXT lcGenFramebuffersEXT -#define glCheckFramebufferStatusEXT lcCheckFramebufferStatusEXT -#define glFramebufferTexture1DEXT lcFramebufferTexture1DEXT -#define glFramebufferTexture2DEXT lcFramebufferTexture2DEXT -#define glFramebufferTexture3DEXT lcFramebufferTexture3DEXT -#define glFramebufferRenderbufferEXT lcFramebufferRenderbufferEXT -#define glGetFramebufferAttachmentParameterivEXT lcGetFramebufferAttachmentParameterivEXT -#define glGenerateMipmapEXT lcGenerateMipmapEXT - -#define glAttachShader lcAttachShader -#define glBindAttribLocation lcBindAttribLocation -#define glCompileShader lcCompileShader -#define glCreateProgram lcCreateProgram -#define glCreateShader lcCreateShader -#define glDeleteProgram lcDeleteProgram -#define glDeleteShader lcDeleteShader -#define glDetachShader lcDetachShader -#define glDisableVertexAttribArray lcDisableVertexAttribArray -#define glEnableVertexAttribArray lcEnableVertexAttribArray -#define glGetActiveAttrib lcGetActiveAttrib -#define glGetActiveUniform lcGetActiveUniform -#define glGetAttachedShaders lcGetAttachedShaders -#define glGetAttribLocation lcGetAttribLocation -#define glGetProgramiv lcGetProgramiv -#define glGetProgramInfoLog lcGetProgramInfoLog -#define glGetShaderiv lcGetShaderiv -#define glGetShaderInfoLog lcGetShaderInfoLog -#define glGetShaderSource lcGetShaderSource -#define glGetUniformLocation lcGetUniformLocation -#define glGetUniformfv lcGetUniformfv -#define glGetUniformiv lcGetUniformiv -#define glGetVertexAttribdv lcGetVertexAttribdv -#define glGetVertexAttribfv lcGetVertexAttribfv -#define glGetVertexAttribiv lcGetVertexAttribiv -#define glGetVertexAttribPointerv lcGetVertexAttribPointerv -#define glIsProgram lcIsProgram -#define glIsShader lcIsShader -#define glLinkProgram lcLinkProgram -#define glShaderSource lcShaderSource -#define glUseProgram lcUseProgram -#define glUniform1f lcUniform1f -#define glUniform2f lcUniform2f -#define glUniform3f lcUniform3f -#define glUniform4f lcUniform4f -#define glUniform1i lcUniform1i -#define glUniform2i lcUniform2i -#define glUniform3i lcUniform3i -#define glUniform4i lcUniform4i -#define glUniform1fv lcUniform1fv -#define glUniform2fv lcUniform2fv -#define glUniform3fv lcUniform3fv -#define glUniform4fv lcUniform4fv -#define glUniform1iv lcUniform1iv -#define glUniform2iv lcUniform2iv -#define glUniform3iv lcUniform3iv -#define glUniform4iv lcUniform4iv -#define glUniformMatrix2fv lcUniformMatrix2fv -#define glUniformMatrix3fv lcUniformMatrix3fv -#define glUniformMatrix4fv lcUniformMatrix4fv -#define glValidateProgram lcValidateProgram -#define glVertexAttribPointer lcVertexAttribPointer - -#endif - -#endif +#ifndef _LC_GLEXTENSIONS_H_ +#define _LC_GLEXTENSIONS_H_ + +void lcInitializeGLExtensions(const QGLContext* Context); + +extern bool gSupportsShaderObjects; +extern bool gSupportsVertexBufferObject; +extern bool gSupportsFramebufferObjectARB; +extern bool gSupportsFramebufferObjectEXT; +extern bool gSupportsAnisotropic; +extern GLfloat gMaxAnisotropy; + +#ifndef Q_OS_MAC +#define LC_LOAD_GLEXTENSIONS +#endif + +#ifdef LC_LOAD_GLEXTENSIONS + +extern PFNGLBINDBUFFERARBPROC lcBindBufferARB; +extern PFNGLDELETEBUFFERSARBPROC lcDeleteBuffersARB; +extern PFNGLGENBUFFERSARBPROC lcGenBuffersARB; +extern PFNGLISBUFFERARBPROC lcIsBufferARB; +extern PFNGLBUFFERDATAARBPROC lcBufferDataARB; +extern PFNGLBUFFERSUBDATAARBPROC lcBufferSubDataARB; +extern PFNGLGETBUFFERSUBDATAARBPROC lcGetBufferSubDataARB; +extern PFNGLMAPBUFFERARBPROC lcMapBufferARB; +extern PFNGLUNMAPBUFFERARBPROC lcUnmapBufferARB; +extern PFNGLGETBUFFERPARAMETERIVARBPROC lcGetBufferParameterivARB; +extern PFNGLGETBUFFERPOINTERVARBPROC lcGetBufferPointervARB; + +extern PFNGLISRENDERBUFFERPROC lcIsRenderbuffer; +extern PFNGLBINDRENDERBUFFERPROC lcBindRenderbuffer; +extern PFNGLDELETERENDERBUFFERSPROC lcDeleteRenderbuffers; +extern PFNGLGENRENDERBUFFERSPROC lcGenRenderbuffers; +extern PFNGLRENDERBUFFERSTORAGEPROC lcRenderbufferStorage; +extern PFNGLGETRENDERBUFFERPARAMETERIVPROC lcGetRenderbufferParameteriv; +extern PFNGLISFRAMEBUFFERPROC lcIsFramebuffer; +extern PFNGLBINDFRAMEBUFFERPROC lcBindFramebuffer; +extern PFNGLDELETEFRAMEBUFFERSPROC lcDeleteFramebuffers; +extern PFNGLGENFRAMEBUFFERSPROC lcGenFramebuffers; +extern PFNGLCHECKFRAMEBUFFERSTATUSPROC lcCheckFramebufferStatus; +extern PFNGLFRAMEBUFFERTEXTURE1DPROC lcFramebufferTexture1D; +extern PFNGLFRAMEBUFFERTEXTURE2DPROC lcFramebufferTexture2D; +extern PFNGLFRAMEBUFFERTEXTURE3DPROC lcFramebufferTexture3D; +extern PFNGLFRAMEBUFFERRENDERBUFFERPROC lcFramebufferRenderbuffer; +extern PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC lcGetFramebufferAttachmentParameteriv; +extern PFNGLGENERATEMIPMAPPROC lcGenerateMipmap; +extern PFNGLBLITFRAMEBUFFERPROC lcBlitFramebuffer; +extern PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC lcRenderbufferStorageMultisample; +extern PFNGLFRAMEBUFFERTEXTURELAYERPROC lcFramebufferTextureLayer; + +extern PFNGLISRENDERBUFFEREXTPROC lcIsRenderbufferEXT; +extern PFNGLBINDRENDERBUFFEREXTPROC lcBindRenderbufferEXT; +extern PFNGLDELETERENDERBUFFERSEXTPROC lcDeleteRenderbuffersEXT; +extern PFNGLGENRENDERBUFFERSEXTPROC lcGenRenderbuffersEXT; +extern PFNGLRENDERBUFFERSTORAGEEXTPROC lcRenderbufferStorageEXT; +extern PFNGLGETRENDERBUFFERPARAMETERIVEXTPROC lcGetRenderbufferParameterivEXT; +extern PFNGLISFRAMEBUFFEREXTPROC lcIsFramebufferEXT; +extern PFNGLBINDFRAMEBUFFEREXTPROC lcBindFramebufferEXT; +extern PFNGLDELETEFRAMEBUFFERSEXTPROC lcDeleteFramebuffersEXT; +extern PFNGLGENFRAMEBUFFERSEXTPROC lcGenFramebuffersEXT; +extern PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC lcCheckFramebufferStatusEXT; +extern PFNGLFRAMEBUFFERTEXTURE1DEXTPROC lcFramebufferTexture1DEXT; +extern PFNGLFRAMEBUFFERTEXTURE2DEXTPROC lcFramebufferTexture2DEXT; +extern PFNGLFRAMEBUFFERTEXTURE3DEXTPROC lcFramebufferTexture3DEXT; +extern PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC lcFramebufferRenderbufferEXT; +extern PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVEXTPROC lcGetFramebufferAttachmentParameterivEXT; +extern PFNGLGENERATEMIPMAPEXTPROC lcGenerateMipmapEXT; + +extern PFNGLATTACHSHADERPROC lcAttachShader; +extern PFNGLBINDATTRIBLOCATIONPROC lcBindAttribLocation; +extern PFNGLCOMPILESHADERPROC lcCompileShader; +extern PFNGLCREATEPROGRAMPROC lcCreateProgram; +extern PFNGLCREATESHADERPROC lcCreateShader; +extern PFNGLDELETEPROGRAMPROC lcDeleteProgram; +extern PFNGLDELETESHADERPROC lcDeleteShader; +extern PFNGLDETACHSHADERPROC lcDetachShader; +extern PFNGLDISABLEVERTEXATTRIBARRAYPROC lcDisableVertexAttribArray; +extern PFNGLENABLEVERTEXATTRIBARRAYPROC lcEnableVertexAttribArray; +extern PFNGLGETACTIVEATTRIBPROC lcGetActiveAttrib; +extern PFNGLGETACTIVEUNIFORMPROC lcGetActiveUniform; +extern PFNGLGETATTACHEDSHADERSPROC lcGetAttachedShaders; +extern PFNGLGETATTRIBLOCATIONPROC lcGetAttribLocation; +extern PFNGLGETPROGRAMIVPROC lcGetProgramiv; +extern PFNGLGETPROGRAMINFOLOGPROC lcGetProgramInfoLog; +extern PFNGLGETSHADERIVPROC lcGetShaderiv; +extern PFNGLGETSHADERINFOLOGPROC lcGetShaderInfoLog; +extern PFNGLGETSHADERSOURCEPROC lcGetShaderSource; +extern PFNGLGETUNIFORMLOCATIONPROC lcGetUniformLocation; +extern PFNGLGETUNIFORMFVPROC lcGetUniformfv; +extern PFNGLGETUNIFORMIVPROC lcGetUniformiv; +extern PFNGLGETVERTEXATTRIBDVPROC lcGetVertexAttribdv; +extern PFNGLGETVERTEXATTRIBFVPROC lcGetVertexAttribfv; +extern PFNGLGETVERTEXATTRIBIVPROC lcGetVertexAttribiv; +extern PFNGLGETVERTEXATTRIBPOINTERVPROC lcGetVertexAttribPointerv; +extern PFNGLISPROGRAMPROC lcIsProgram; +extern PFNGLISSHADERPROC lcIsShader; +extern PFNGLLINKPROGRAMPROC lcLinkProgram; +extern PFNGLSHADERSOURCEPROC lcShaderSource; +extern PFNGLUSEPROGRAMPROC lcUseProgram; +extern PFNGLUNIFORM1FPROC lcUniform1f; +extern PFNGLUNIFORM2FPROC lcUniform2f; +extern PFNGLUNIFORM3FPROC lcUniform3f; +extern PFNGLUNIFORM4FPROC lcUniform4f; +extern PFNGLUNIFORM1IPROC lcUniform1i; +extern PFNGLUNIFORM2IPROC lcUniform2i; +extern PFNGLUNIFORM3IPROC lcUniform3i; +extern PFNGLUNIFORM4IPROC lcUniform4i; +extern PFNGLUNIFORM1FVPROC lcUniform1fv; +extern PFNGLUNIFORM2FVPROC lcUniform2fv; +extern PFNGLUNIFORM3FVPROC lcUniform3fv; +extern PFNGLUNIFORM4FVPROC lcUniform4fv; +extern PFNGLUNIFORM1IVPROC lcUniform1iv; +extern PFNGLUNIFORM2IVPROC lcUniform2iv; +extern PFNGLUNIFORM3IVPROC lcUniform3iv; +extern PFNGLUNIFORM4IVPROC lcUniform4iv; +extern PFNGLUNIFORMMATRIX2FVPROC lcUniformMatrix2fv; +extern PFNGLUNIFORMMATRIX3FVPROC lcUniformMatrix3fv; +extern PFNGLUNIFORMMATRIX4FVPROC lcUniformMatrix4fv; +extern PFNGLVALIDATEPROGRAMPROC lcValidateProgram; +extern PFNGLVERTEXATTRIBPOINTERPROC lcVertexAttribPointer; + +#define glBindBuffer lcBindBufferARB +#define glDeleteBuffers lcDeleteBuffersARB +#define glGenBuffers lcGenBuffersARB +#define glIsBuffer lcIsBufferARB +#define glBufferData lcBufferDataARB +#define glBufferSubData lcBufferSubDataARB +#define glGetBufferSubData lcGetBufferSubDataARB +#define glMapBuffer lcMapBufferARB +#define glUnmapBuffer lcUnmapBufferARB +#define glGetBufferParameteriv lcGetBufferParameterivARB +#define glGetBufferPointerv lcGetBufferPointervARB + +#define glIsRenderbuffer lcIsRenderbuffer +#define glBindRenderbuffer lcBindRenderbuffer +#define glDeleteRenderbuffers lcDeleteRenderbuffers +#define glGenRenderbuffers lcGenRenderbuffers +#define glRenderbufferStorage lcRenderbufferStorage +#define glGetRenderbufferParameteriv lcGetRenderbufferParameteriv +#define glIsFramebuffer lcIsFramebuffer +#define glBindFramebuffer lcBindFramebuffer +#define glDeleteFramebuffers lcDeleteFramebuffers +#define glGenFramebuffers lcGenFramebuffers +#define glCheckFramebufferStatus lcCheckFramebufferStatus +#define glFramebufferTexture1D lcFramebufferTexture1D +#define glFramebufferTexture2D lcFramebufferTexture2D +#define glFramebufferTexture3D lcFramebufferTexture3D +#define glFramebufferRenderbuffer lcFramebufferRenderbuffer +#define glGetFramebufferAttachmentParameteriv lcGetFramebufferAttachmentParameteriv +#define glGenerateMipmap lcGenerateMipmap +#define glBlitFramebuffer lcBlitFramebuffer +#define glRenderbufferStorageMultisample lcRenderbufferStorageMultisample +#define glFramebufferTextureLayer lcFramebufferTextureLayer + +#define glIsRenderbufferEXT lcIsRenderbufferEXT +#define glBindRenderbufferEXT lcBindRenderbufferEXT +#define glDeleteRenderbuffersEXT lcDeleteRenderbuffersEXT +#define glGenRenderbuffersEXT lcGenRenderbuffersEXT +#define glRenderbufferStorageEXT lcRenderbufferStorageEXT +#define glGetRenderbufferParameterivEXT lcGetRenderbufferParameterivEXT +#define glIsFramebufferEXT lcIsFramebufferEXT +#define glBindFramebufferEXT lcBindFramebufferEXT +#define glDeleteFramebuffersEXT lcDeleteFramebuffersEXT +#define glGenFramebuffersEXT lcGenFramebuffersEXT +#define glCheckFramebufferStatusEXT lcCheckFramebufferStatusEXT +#define glFramebufferTexture1DEXT lcFramebufferTexture1DEXT +#define glFramebufferTexture2DEXT lcFramebufferTexture2DEXT +#define glFramebufferTexture3DEXT lcFramebufferTexture3DEXT +#define glFramebufferRenderbufferEXT lcFramebufferRenderbufferEXT +#define glGetFramebufferAttachmentParameterivEXT lcGetFramebufferAttachmentParameterivEXT +#define glGenerateMipmapEXT lcGenerateMipmapEXT + +#define glAttachShader lcAttachShader +#define glBindAttribLocation lcBindAttribLocation +#define glCompileShader lcCompileShader +#define glCreateProgram lcCreateProgram +#define glCreateShader lcCreateShader +#define glDeleteProgram lcDeleteProgram +#define glDeleteShader lcDeleteShader +#define glDetachShader lcDetachShader +#define glDisableVertexAttribArray lcDisableVertexAttribArray +#define glEnableVertexAttribArray lcEnableVertexAttribArray +#define glGetActiveAttrib lcGetActiveAttrib +#define glGetActiveUniform lcGetActiveUniform +#define glGetAttachedShaders lcGetAttachedShaders +#define glGetAttribLocation lcGetAttribLocation +#define glGetProgramiv lcGetProgramiv +#define glGetProgramInfoLog lcGetProgramInfoLog +#define glGetShaderiv lcGetShaderiv +#define glGetShaderInfoLog lcGetShaderInfoLog +#define glGetShaderSource lcGetShaderSource +#define glGetUniformLocation lcGetUniformLocation +#define glGetUniformfv lcGetUniformfv +#define glGetUniformiv lcGetUniformiv +#define glGetVertexAttribdv lcGetVertexAttribdv +#define glGetVertexAttribfv lcGetVertexAttribfv +#define glGetVertexAttribiv lcGetVertexAttribiv +#define glGetVertexAttribPointerv lcGetVertexAttribPointerv +#define glIsProgram lcIsProgram +#define glIsShader lcIsShader +#define glLinkProgram lcLinkProgram +#define glShaderSource lcShaderSource +#define glUseProgram lcUseProgram +#define glUniform1f lcUniform1f +#define glUniform2f lcUniform2f +#define glUniform3f lcUniform3f +#define glUniform4f lcUniform4f +#define glUniform1i lcUniform1i +#define glUniform2i lcUniform2i +#define glUniform3i lcUniform3i +#define glUniform4i lcUniform4i +#define glUniform1fv lcUniform1fv +#define glUniform2fv lcUniform2fv +#define glUniform3fv lcUniform3fv +#define glUniform4fv lcUniform4fv +#define glUniform1iv lcUniform1iv +#define glUniform2iv lcUniform2iv +#define glUniform3iv lcUniform3iv +#define glUniform4iv lcUniform4iv +#define glUniformMatrix2fv lcUniformMatrix2fv +#define glUniformMatrix3fv lcUniformMatrix3fv +#define glUniformMatrix4fv lcUniformMatrix4fv +#define glValidateProgram lcValidateProgram +#define glVertexAttribPointer lcVertexAttribPointer + +#endif + +#endif diff --git a/common/lc_library.cpp b/common/lc_library.cpp index 33e12813..8b99af00 100644 --- a/common/lc_library.cpp +++ b/common/lc_library.cpp @@ -1425,9 +1425,9 @@ bool lcPiecesLibrary::LoadAndInlineFile(const char* FileName, lcMemFile& File) TempProject.Save(Stream); Stream.flush(); - File.Seek(0, SEEK_SET); - File.WriteBuffer(Data.constData(), Data.size()); - File.Seek(0, SEEK_SET); + File.Seek(0, SEEK_SET); + File.WriteBuffer(Data.constData(), Data.size()); + File.Seek(0, SEEK_SET); return true; } diff --git a/common/lc_model.cpp b/common/lc_model.cpp index 9f143f44..5c2b15ce 100644 --- a/common/lc_model.cpp +++ b/common/lc_model.cpp @@ -1,3982 +1,3982 @@ -#include "lc_global.h" -#include "lc_model.h" -#include -#include "piece.h" -#include "camera.h" -#include "light.h" -#include "group.h" -#include "lc_mainwindow.h" -#include "lc_profile.h" -#include "lc_library.h" -#include "lc_texture.h" -#include "lc_synth.h" -#include "lc_file.h" -#include "pieceinf.h" -#include "view.h" -#include "preview.h" -#include "minifig.h" -#include "lc_qarraydialog.h" -#include "lc_qselectdialog.h" -#include "lc_qminifigdialog.h" -#include "lc_qgroupdialog.h" -#include "lc_qeditgroupsdialog.h" -#include "lc_qutils.h" - -void lcModelProperties::LoadDefaults() -{ - mAuthor = lcGetProfileString(LC_PROFILE_DEFAULT_AUTHOR_NAME); - - mBackgroundType = (lcBackgroundType)lcGetProfileInt(LC_PROFILE_DEFAULT_BACKGROUND_TYPE); - mBackgroundSolidColor = lcVector3FromColor(lcGetProfileInt(LC_PROFILE_DEFAULT_BACKGROUND_COLOR)); - mBackgroundGradientColor1 = lcVector3FromColor(lcGetProfileInt(LC_PROFILE_DEFAULT_GRADIENT_COLOR1)); - mBackgroundGradientColor2 = lcVector3FromColor(lcGetProfileInt(LC_PROFILE_DEFAULT_GRADIENT_COLOR2)); - mBackgroundImage = lcGetProfileString(LC_PROFILE_DEFAULT_BACKGROUND_TEXTURE); - mBackgroundImageTile = lcGetProfileInt(LC_PROFILE_DEFAULT_BACKGROUND_TILE); - - mFogEnabled = lcGetProfileInt(LC_PROFILE_DEFAULT_FOG_ENABLED); - mFogDensity = lcGetProfileFloat(LC_PROFILE_DEFAULT_FOG_DENSITY); - mFogColor = lcVector3FromColor(lcGetProfileInt(LC_PROFILE_DEFAULT_FOG_COLOR)); - mAmbientColor = lcVector3FromColor(lcGetProfileInt(LC_PROFILE_DEFAULT_AMBIENT_COLOR)); -} - -void lcModelProperties::SaveDefaults() -{ - lcSetProfileInt(LC_PROFILE_DEFAULT_BACKGROUND_TYPE, mBackgroundType); - lcSetProfileInt(LC_PROFILE_DEFAULT_BACKGROUND_COLOR, lcColorFromVector3(mBackgroundSolidColor)); - lcSetProfileInt(LC_PROFILE_DEFAULT_GRADIENT_COLOR1, lcColorFromVector3(mBackgroundGradientColor1)); - lcSetProfileInt(LC_PROFILE_DEFAULT_GRADIENT_COLOR2, lcColorFromVector3(mBackgroundGradientColor2)); - lcSetProfileString(LC_PROFILE_DEFAULT_BACKGROUND_TEXTURE, mBackgroundImage); - lcSetProfileInt(LC_PROFILE_DEFAULT_BACKGROUND_TILE, mBackgroundImageTile); - - lcSetProfileInt(LC_PROFILE_DEFAULT_FOG_ENABLED, mFogEnabled); - lcSetProfileFloat(LC_PROFILE_DEFAULT_FOG_DENSITY, mFogDensity); - lcSetProfileInt(LC_PROFILE_DEFAULT_FOG_COLOR, lcColorFromVector3(mFogColor)); - lcSetProfileInt(LC_PROFILE_DEFAULT_AMBIENT_COLOR, lcColorFromVector3(mAmbientColor)); -} - -void lcModelProperties::SaveLDraw(QTextStream& Stream) const -{ - QLatin1String LineEnding("\r\n"); - - if (!mAuthor.isEmpty()) - Stream << QLatin1String("0 !LEOCAD MODEL AUTHOR ") << mAuthor << LineEnding; - - if (!mDescription.isEmpty()) - Stream << QLatin1String("0 !LEOCAD MODEL DESCRIPTION ") << mDescription << LineEnding; - - if (!mComments.isEmpty()) - { - QStringList Comments = mComments.split('\n'); - foreach (const QString& Comment, Comments) - Stream << QLatin1String("0 !LEOCAD MODEL COMMENT ") << Comment << LineEnding; - } - - bool TypeChanged = (mBackgroundType != lcGetDefaultProfileInt(LC_PROFILE_DEFAULT_BACKGROUND_TYPE)); - - switch (mBackgroundType) - { - case LC_BACKGROUND_SOLID: - if (mBackgroundSolidColor != lcVector3FromColor(lcGetDefaultProfileInt(LC_PROFILE_DEFAULT_BACKGROUND_COLOR)) || TypeChanged) - Stream << QLatin1String("0 !LEOCAD MODEL BACKGROUND COLOR ") << mBackgroundSolidColor[0] << ' ' << mBackgroundSolidColor[1] << ' ' << mBackgroundSolidColor[2] << LineEnding; - break; - - case LC_BACKGROUND_GRADIENT: - if (mBackgroundGradientColor1 != lcVector3FromColor(lcGetProfileInt(LC_PROFILE_DEFAULT_GRADIENT_COLOR1)) || - mBackgroundGradientColor2 != lcVector3FromColor(lcGetProfileInt(LC_PROFILE_DEFAULT_GRADIENT_COLOR2)) || TypeChanged) - Stream << QLatin1String("0 !LEOCAD MODEL BACKGROUND GRADIENT ") << mBackgroundGradientColor1[0] << ' ' << mBackgroundGradientColor1[1] << ' ' << mBackgroundGradientColor1[2] << ' ' << mBackgroundGradientColor2[0] << ' ' << mBackgroundGradientColor2[1] << ' ' << mBackgroundGradientColor2[2] << LineEnding; - break; - - case LC_BACKGROUND_IMAGE: - if (!mBackgroundImage.isEmpty()) - { - Stream << QLatin1String("0 !LEOCAD MODEL BACKGROUND IMAGE "); - if (mBackgroundImageTile) - Stream << QLatin1String("TILE "); - Stream << QLatin1String("NAME ") << mBackgroundImage << LineEnding; - } - break; - } - -// bool mFogEnabled; -// float mFogDensity; -// lcVector3 mFogColor; -// lcVector3 mAmbientColor; -} - -void lcModelProperties::ParseLDrawLine(QTextStream& Stream) -{ - QString Token; - Stream >> Token; - - if (Token == QLatin1String("AUTHOR")) - mAuthor = Stream.readLine().mid(1); - else if (Token == QLatin1String("DESCRIPTION")) - mDescription = Stream.readLine().mid(1); - else if (Token == QLatin1String("COMMENT")) - { - QString Comment = Stream.readLine().mid(1); - if (!mComments.isEmpty()) - mComments += '\n'; - mComments += Comment; - } - else if (Token == QLatin1String("BACKGROUND")) - { - Stream >> Token; - - if (Token == QLatin1String("COLOR")) - { - mBackgroundType = LC_BACKGROUND_SOLID; - Stream >> mBackgroundSolidColor[0] >> mBackgroundSolidColor[1] >> mBackgroundSolidColor[2]; - } - else if (Token == QLatin1String("GRADIENT")) - { - mBackgroundType = LC_BACKGROUND_GRADIENT; - Stream >> mBackgroundGradientColor1[0] >> mBackgroundGradientColor1[1] >> mBackgroundGradientColor1[2] >> mBackgroundGradientColor2[0] >> mBackgroundGradientColor2[1] >> mBackgroundGradientColor2[2]; - } - else if (Token == QLatin1String("IMAGE")) - { - Stream >> Token; - - if (Token == QLatin1String("TILE")) - { - mBackgroundImageTile = true; - Stream >> Token; - } - - if (Token == QLatin1String("NAME")) - mBackgroundImage = Stream.readLine().trimmed(); - } - } -} - -lcModel::lcModel(const QString& Name) -{ - mProperties.mName = Name; - mProperties.LoadDefaults(); - - mActive = false; - mCurrentStep = 1; - mBackgroundTexture = NULL; - mPieceInfo = NULL; -} - -lcModel::~lcModel() -{ - if (mPieceInfo) - { - if (gMainWindow && gMainWindow->mPreviewWidget->GetCurrentPiece() == mPieceInfo) - gMainWindow->mPreviewWidget->SetDefaultPiece(); - - if (mPieceInfo->GetModel() == this) - mPieceInfo->SetPlaceholder(); - mPieceInfo->Release(true); - } - - DeleteModel(); - DeleteHistory(); -} - -bool lcModel::IncludesModel(const lcModel* Model) const -{ - if (Model == this) - return true; - - for (int PieceIdx = 0; PieceIdx < mPieces.GetSize(); PieceIdx++) - if (mPieces[PieceIdx]->mPieceInfo->IncludesModel(Model)) - return true; - - return false; -} - -void lcModel::DeleteHistory() -{ - mUndoHistory.DeleteAll(); - mRedoHistory.DeleteAll(); -} - -void lcModel::DeleteModel() -{ - lcReleaseTexture(mBackgroundTexture); - mBackgroundTexture = NULL; - - if (gMainWindow) - { - const lcArray* Views = gMainWindow->GetViewsForModel(this); - - // TODO: this is only needed to avoid a dangling pointer during undo/redo if a camera is set to a view but we should find a better solution instead - if (Views) - { - for (int ViewIdx = 0; ViewIdx < Views->GetSize(); ViewIdx++) - { - View* View = (*Views)[ViewIdx]; - lcCamera* Camera = View->mCamera; - - if (!Camera->IsSimple() && mCameras.FindIndex(Camera) != -1) - View->SetCamera(Camera, true); - } - } - } - - mPieces.DeleteAll(); - mCameras.DeleteAll(); - mLights.DeleteAll(); - mGroups.DeleteAll(); - mFileLines.clear(); -} - -void lcModel::CreatePieceInfo(Project* Project) -{ - mPieceInfo = lcGetPiecesLibrary()->FindPiece(mProperties.mName.toUpper().toLatin1().constData(), Project, true); - mPieceInfo->SetModel(this, true); - mPieceInfo->AddRef(); -} - -void lcModel::UpdatePieceInfo(lcArray& UpdatedModels) -{ - if (UpdatedModels.FindIndex(this) != -1) - return; - - mPieceInfo->SetModel(this, false); - UpdatedModels.Add(this); - - lcMesh* Mesh = mPieceInfo->GetMesh(); - - if (mPieces.IsEmpty() && !Mesh) - { - mPieceInfo->SetBoundingBox(lcVector3(0.0f, 0.0f, 0.0f), lcVector3(0.0f, 0.0f, 0.0f)); - return; - } - - lcVector3 Min(FLT_MAX, FLT_MAX, FLT_MAX), Max(-FLT_MAX, -FLT_MAX, -FLT_MAX); - - for (int PieceIdx = 0; PieceIdx < mPieces.GetSize(); PieceIdx++) - { - lcPiece* Piece = mPieces[PieceIdx]; - - if (Piece->GetStepHide() == LC_STEP_MAX) - { - Piece->mPieceInfo->UpdateBoundingBox(UpdatedModels); - Piece->CompareBoundingBox(Min, Max); - } - } - - if (Mesh) - { - Min = lcMin(Min, Mesh->mBoundingBox.Min); - Max = lcMax(Max, Mesh->mBoundingBox.Max); - } - - mPieceInfo->SetBoundingBox(Min, Max); -} - -void lcModel::SaveLDraw(QTextStream& Stream, bool SelectedOnly) const -{ - QLatin1String LineEnding("\r\n"); - - mProperties.SaveLDraw(Stream); - - if (mCurrentStep != GetLastStep()) - Stream << QLatin1String("0 !LEOCAD MODEL CURRENT_STEP") << mCurrentStep << LineEnding; - - lcArray CurrentGroups; - lcStep Step = 1; - int CurrentLine = 0; - - for (int PieceIdx = 0; PieceIdx < mPieces.GetSize(); PieceIdx++) - { - lcPiece* Piece = mPieces[PieceIdx]; - - if (SelectedOnly && !Piece->IsSelected()) - continue; - - while (Piece->GetFileLine() > CurrentLine && CurrentLine < mFileLines.size()) - { - QString Line = mFileLines[CurrentLine]; - QTextStream LineStream(&Line, QIODevice::ReadOnly); - - QString Token; - LineStream >> Token; - bool Skip = false; - - if (Token == QLatin1String("0")) - { - LineStream >> Token; - - if (Token == QLatin1String("STEP")) - { - if (Piece->GetStepShow() > Step) - Step++; - else - Skip = true; - } - } - - if (!Skip) - Stream << mFileLines[CurrentLine]; - CurrentLine++; - } - - while (Piece->GetStepShow() > Step) - { - Stream << QLatin1String("0 STEP\r\n"); - Step++; - } - - lcGroup* PieceGroup = Piece->GetGroup(); - - if (PieceGroup) - { - if (CurrentGroups.IsEmpty() || (!CurrentGroups.IsEmpty() && PieceGroup != CurrentGroups[CurrentGroups.GetSize() - 1])) - { - lcArray PieceParents; - - for (lcGroup* Group = PieceGroup; Group; Group = Group->mGroup) - PieceParents.InsertAt(0, Group); - - int FoundParent = -1; - - while (!CurrentGroups.IsEmpty()) - { - lcGroup* Group = CurrentGroups[CurrentGroups.GetSize() - 1]; - int Index = PieceParents.FindIndex(Group); - - if (Index == -1) - { - CurrentGroups.RemoveIndex(CurrentGroups.GetSize() - 1); - Stream << QLatin1String("0 !LEOCAD GROUP END\r\n"); - } - else - { - FoundParent = Index; - break; - } - } - - for (int ParentIdx = FoundParent + 1; ParentIdx < PieceParents.GetSize(); ParentIdx++) - { - lcGroup* Group = PieceParents[ParentIdx]; - CurrentGroups.Add(Group); - Stream << QLatin1String("0 !LEOCAD GROUP BEGIN ") << Group->mName << LineEnding; - } - } - } - else - { - while (CurrentGroups.GetSize()) - { - CurrentGroups.RemoveIndex(CurrentGroups.GetSize() - 1); - Stream << QLatin1String("0 !LEOCAD GROUP END\r\n"); - } - } - - if (Piece->mPieceInfo->GetSynthInfo()) - { - Stream << QLatin1String("0 !LEOCAD SYNTH BEGIN\r\n"); - - const lcArray& ControlPoints = Piece->GetControlPoints(); - for (int ControlPointIdx = 0; ControlPointIdx < ControlPoints.GetSize(); ControlPointIdx++) - { - const lcPieceControlPoint& ControlPoint = ControlPoints[ControlPointIdx]; - - Stream << QLatin1String("0 !LEOCAD SYNTH CONTROL_POINT"); - - const float* FloatMatrix = ControlPoint.Transform; - float Numbers[13] = { FloatMatrix[12], -FloatMatrix[14], FloatMatrix[13], FloatMatrix[0], -FloatMatrix[8], FloatMatrix[4], -FloatMatrix[2], FloatMatrix[10], -FloatMatrix[6], FloatMatrix[1], -FloatMatrix[9], FloatMatrix[5], ControlPoint.Scale }; - - for (int NumberIdx = 0; NumberIdx < 13; NumberIdx++) - Stream << ' ' << lcFormatValue(Numbers[NumberIdx]); - - Stream << LineEnding; - } - } - - Piece->SaveLDraw(Stream); - - if (Piece->mPieceInfo->GetSynthInfo()) - Stream << QLatin1String("0 !LEOCAD SYNTH END\r\n"); - } - - while (CurrentLine < mFileLines.size()) - { - Stream << mFileLines[CurrentLine]; - CurrentLine++; - } - - while (CurrentGroups.GetSize()) - { - CurrentGroups.RemoveIndex(CurrentGroups.GetSize() - 1); - Stream << QLatin1String("0 !LEOCAD GROUP END\r\n"); - } - - for (int CameraIdx = 0; CameraIdx < mCameras.GetSize(); CameraIdx++) - { - lcCamera* Camera = mCameras[CameraIdx]; - - if (!SelectedOnly || Camera->IsSelected()) - Camera->SaveLDraw(Stream); - } - - for (int LightIdx = 0; LightIdx < mLights.GetSize(); LightIdx++) - { - lcLight* Light = mLights[LightIdx]; - - if (!SelectedOnly || Light->IsSelected()) - Light->SaveLDraw(Stream); - } - - Stream.flush(); -} - -void lcModel::LoadLDraw(QIODevice& Device, Project* Project) -{ - lcPiece* Piece = NULL; - lcCamera* Camera = NULL; - lcLight* Light = NULL; - lcArray CurrentGroups; - lcArray ControlPoints; - int CurrentStep = 1; - - mProperties.mAuthor.clear(); - - while (!Device.atEnd()) - { - qint64 Pos = Device.pos(); - QString OriginalLine = Device.readLine(); - QString Line = OriginalLine.trimmed(); - QTextStream LineStream(&Line, QIODevice::ReadOnly); - - QString Token; - LineStream >> Token; - - if (Token == QLatin1String("0")) - { - LineStream >> Token; - - if (Token == QLatin1String("FILE")) - { - if (!mProperties.mName.isEmpty()) - { - Device.seek(Pos); - break; - } - - mProperties.mName = LineStream.readAll().trimmed(); - continue; - } - else if (Token == QLatin1String("NOFILE")) - { - break; - } - else if (Token == QLatin1String("STEP")) - { - CurrentStep++; - mFileLines.append(OriginalLine); - continue; - } - - if (Token != QLatin1String("!LEOCAD")) - { - mFileLines.append(OriginalLine); - continue; - } - - LineStream >> Token; - - if (Token == QLatin1String("MODEL")) - { - mProperties.ParseLDrawLine(LineStream); - } - else if (Token == QLatin1String("PIECE")) - { - if (!Piece) - Piece = new lcPiece(NULL); - - Piece->ParseLDrawLine(LineStream); - } - else if (Token == QLatin1String("CAMERA")) - { - if (!Camera) - Camera = new lcCamera(false); - - if (Camera->ParseLDrawLine(LineStream)) - { - Camera->CreateName(mCameras); - mCameras.Add(Camera); - Camera = NULL; - } - } - else if (Token == QLatin1String("LIGHT")) - { - } - else if (Token == QLatin1String("GROUP")) - { - LineStream >> Token; - - if (Token == QLatin1String("BEGIN")) - { - QString Name = LineStream.readAll().trimmed(); - QByteArray NameUtf = Name.toUtf8(); // todo: replace with qstring - lcGroup* Group = GetGroup(NameUtf.constData(), true); - if (!CurrentGroups.IsEmpty()) - Group->mGroup = CurrentGroups[CurrentGroups.GetSize() - 1]; - else - Group->mGroup = NULL; - CurrentGroups.Add(Group); - } - else if (Token == QLatin1String("END")) - { - if (!CurrentGroups.IsEmpty()) - CurrentGroups.RemoveIndex(CurrentGroups.GetSize() - 1); - } - } - else if (Token == QLatin1String("SYNTH")) - { - LineStream >> Token; - - if (Token == QLatin1String("BEGIN")) - { - ControlPoints.RemoveAll(); - } - else if (Token == QLatin1String("END")) - { - ControlPoints.RemoveAll(); - } - else if (Token == QLatin1String("CONTROL_POINT")) - { - float Numbers[13]; - for (int TokenIdx = 0; TokenIdx < 13; TokenIdx++) - LineStream >> Numbers[TokenIdx]; - - lcPieceControlPoint& PieceControlPoint = ControlPoints.Add(); - PieceControlPoint.Transform = lcMatrix44(lcVector4(Numbers[3], Numbers[9], -Numbers[6], 0.0f), lcVector4(Numbers[5], Numbers[11], -Numbers[8], 0.0f), - lcVector4(-Numbers[4], -Numbers[10], Numbers[7], 0.0f), lcVector4(Numbers[0], Numbers[2], -Numbers[1], 1.0f)); - PieceControlPoint.Scale = Numbers[12]; - } - } - - continue; - } - else if (Token == QLatin1String("1")) - { - int ColorCode; - LineStream >> ColorCode; - - float IncludeMatrix[12]; - for (int TokenIdx = 0; TokenIdx < 12; TokenIdx++) - LineStream >> IncludeMatrix[TokenIdx]; - - lcMatrix44 IncludeTransform(lcVector4(IncludeMatrix[3], IncludeMatrix[6], IncludeMatrix[9], 0.0f), lcVector4(IncludeMatrix[4], IncludeMatrix[7], IncludeMatrix[10], 0.0f), - lcVector4(IncludeMatrix[5], IncludeMatrix[8], IncludeMatrix[11], 0.0f), lcVector4(IncludeMatrix[0], IncludeMatrix[1], IncludeMatrix[2], 1.0f)); - - QString File = LineStream.readAll().trimmed().toUpper(); - QString PartID = File; - PartID.replace('\\', '/'); - - if (PartID.endsWith(QLatin1String(".DAT"))) - PartID = PartID.left(PartID.size() - 4); - - lcPiecesLibrary* Library = lcGetPiecesLibrary(); - - if (Library->IsPrimitive(PartID.toLatin1().constData())) - { - mFileLines.append(OriginalLine); - } - else - { - if (!Piece) - Piece = new lcPiece(NULL); - - if (!CurrentGroups.IsEmpty()) - Piece->SetGroup(CurrentGroups[CurrentGroups.GetSize() - 1]); - - PieceInfo* Info = Library->FindPiece(PartID.toLatin1().constData(), Project, false); - - if (!Info) - Info = Library->FindPiece(File.toLatin1().constData(), Project, true); - - float* Matrix = IncludeTransform; - lcMatrix44 Transform(lcVector4(Matrix[0], Matrix[2], -Matrix[1], 0.0f), lcVector4(Matrix[8], Matrix[10], -Matrix[9], 0.0f), - lcVector4(-Matrix[4], -Matrix[6], Matrix[5], 0.0f), lcVector4(Matrix[12], Matrix[14], -Matrix[13], 1.0f)); - - Piece->SetFileLine(mFileLines.size()); - Piece->SetPieceInfo(Info); - Piece->Initialize(Transform, CurrentStep); - Piece->SetColorCode(ColorCode); - Piece->SetControlPoints(ControlPoints); - AddPiece(Piece); - Piece = NULL; - } - } - else - mFileLines.append(OriginalLine); - } - - mCurrentStep = CurrentStep; - CalculateStep(mCurrentStep); - UpdateBackgroundTexture(); - lcGetPiecesLibrary()->UnloadUnusedParts(); - - delete Piece; - delete Camera; - delete Light; -} - -bool lcModel::LoadBinary(lcFile* file) -{ - lcint32 i, count; - char id[32]; - lcuint32 rgb; - float fv = 0.4f; - lcuint8 ch; - lcuint16 sh; - - file->Seek(0, SEEK_SET); - file->ReadBuffer(id, 32); - sscanf(&id[7], "%f", &fv); - - if (fv == 0.0f) - { - lconv *loc = localeconv(); - id[8] = loc->decimal_point[0]; - sscanf(&id[7], "%f", &fv); - - if (fv == 0.0f) - return false; - } - - if (fv > 0.4f) - file->ReadFloats(&fv, 1); - - file->ReadU32(&rgb, 1); - mProperties.mBackgroundSolidColor[0] = (float)((unsigned char) (rgb))/255; - mProperties.mBackgroundSolidColor[1] = (float)((unsigned char) (((unsigned short) (rgb)) >> 8))/255; - mProperties.mBackgroundSolidColor[2] = (float)((unsigned char) ((rgb) >> 16))/255; - - if (fv < 0.6f) // old view - { - double eye[3], target[3]; - file->ReadDoubles(eye, 3); - file->ReadDoubles(target, 3); - } - - file->Seek(28, SEEK_CUR); - file->ReadS32(&i, 1); - mCurrentStep = i; - - if (fv > 0.8f) - file->ReadU32();//m_nScene - - file->ReadS32(&count, 1); - lcPiecesLibrary* Library = lcGetPiecesLibrary(); - - int FirstNewPiece = mPieces.GetSize(); - - while (count--) - { - if (fv > 0.4f) - { - lcPiece* pPiece = new lcPiece(NULL); - pPiece->FileLoad(*file); - AddPiece(pPiece); - } - else - { - char name[LC_PIECE_NAME_LEN]; - lcVector3 pos, rot; - lcuint8 color, step, group; - - file->ReadFloats(pos, 3); - file->ReadFloats(rot, 3); - file->ReadU8(&color, 1); - file->ReadBuffer(name, 9); - file->ReadU8(&step, 1); - file->ReadU8(&group, 1); - - pos *= 25.0f; - lcMatrix44 WorldMatrix = lcMul(lcMatrix44RotationZ(rot[2] * LC_DTOR), lcMul(lcMatrix44RotationY(rot[1] * LC_DTOR), lcMatrix44RotationX(rot[0] * LC_DTOR))); - WorldMatrix.SetTranslation(pos); - - PieceInfo* pInfo = Library->FindPiece(name, NULL, true); - lcPiece* pPiece = new lcPiece(pInfo); - - pPiece->Initialize(WorldMatrix, step); - pPiece->SetColorCode(lcGetColorCodeFromOriginalColor(color)); - AddPiece(pPiece); - -// pPiece->SetGroup((lcGroup*)group); - } - } - - if (fv >= 0.4f) - { - file->ReadBuffer(&ch, 1); - if (ch == 0xFF) file->ReadU16(&sh, 1); else sh = ch; - if (sh > 100) - file->Seek(sh, SEEK_CUR); - else - { - String Author; - file->ReadBuffer(Author.GetBuffer(sh), sh); - Author.Buffer()[sh] = 0; - mProperties.mAuthor = QString::fromUtf8(Author.Buffer()); - } - - file->ReadBuffer(&ch, 1); - if (ch == 0xFF) file->ReadU16(&sh, 1); else sh = ch; - if (sh > 100) - file->Seek(sh, SEEK_CUR); - else - { - String Description; - file->ReadBuffer(Description.GetBuffer(sh), sh); - Description.Buffer()[sh] = 0; - mProperties.mDescription = QString::fromUtf8(Description.Buffer()); - } - - file->ReadBuffer(&ch, 1); - if (ch == 0xFF && fv < 1.3f) file->ReadU16(&sh, 1); else sh = ch; - if (sh > 255) - file->Seek(sh, SEEK_CUR); - else - { - String Comments; - file->ReadBuffer(Comments.GetBuffer(sh), sh); - Comments.Buffer()[sh] = 0; - mProperties.mComments = QString::fromUtf8(Comments.Buffer()); - mProperties.mComments.replace(QLatin1String("\r\n"), QLatin1String("\n")); - } - } - - if (fv >= 0.5f) - { - int NumGroups = mGroups.GetSize(); - - file->ReadS32(&count, 1); - for (i = 0; i < count; i++) - mGroups.Add(new lcGroup()); - - for (int GroupIdx = NumGroups; GroupIdx < mGroups.GetSize(); GroupIdx++) - { - lcGroup* Group = mGroups[GroupIdx]; - - if (fv < 1.0f) - { - char Name[LC_MAX_GROUP_NAME + 1]; - file->ReadBuffer(Name, sizeof(Name)); - Group->mName = QString::fromUtf8(Name); - file->ReadBuffer(&ch, 1); - Group->mGroup = (lcGroup*)-1; - } - else - Group->FileLoad(file); - } - - for (int GroupIdx = NumGroups; GroupIdx < mGroups.GetSize(); GroupIdx++) - { - lcGroup* Group = mGroups[GroupIdx]; - - i = LC_POINTER_TO_INT(Group->mGroup); - Group->mGroup = NULL; - - if (i > 0xFFFF || i == -1) - continue; - - Group->mGroup = mGroups[NumGroups + i]; - } - - for (int PieceIdx = FirstNewPiece; PieceIdx < mPieces.GetSize(); PieceIdx++) - { - lcPiece* Piece = mPieces[PieceIdx]; - - i = LC_POINTER_TO_INT(Piece->GetGroup()); - Piece->SetGroup(NULL); - - if (i > 0xFFFF || i == -1) - continue; - - Piece->SetGroup(mGroups[NumGroups + i]); - } - - RemoveEmptyGroups(); - } - - if (fv >= 0.6f) - { - if (fv < 1.0f) - file->Seek(4, SEEK_CUR); - else - file->Seek(2, SEEK_CUR); - - file->ReadS32(&count, 1); - for (i = 0; i < count; i++) - mCameras.Add(new lcCamera(false)); - - if (count < 7) - { - lcCamera* pCam = new lcCamera(false); - for (i = 0; i < count; i++) - pCam->FileLoad(*file); - delete pCam; - } - else - { - for (int CameraIdx = 0; CameraIdx < mCameras.GetSize(); CameraIdx++) - mCameras[CameraIdx]->FileLoad(*file); - } - } - - if (fv >= 0.7f) - { - file->Seek(16, SEEK_CUR); - - file->ReadU32(&rgb, 1); - mProperties.mFogColor[0] = (float)((unsigned char) (rgb))/255; - mProperties.mFogColor[1] = (float)((unsigned char) (((unsigned short) (rgb)) >> 8))/255; - mProperties.mFogColor[2] = (float)((unsigned char) ((rgb) >> 16))/255; - - if (fv < 1.0f) - { - file->ReadU32(&rgb, 1); - mProperties.mFogDensity = (float)rgb/100; - } - else - file->ReadFloats(&mProperties.mFogDensity, 1); - - if (fv < 1.3f) - { - file->ReadU8(&ch, 1); - if (ch == 0xFF) - file->ReadU16(&sh, 1); - sh = ch; - } - else - file->ReadU16(&sh, 1); - - if (sh < LC_MAXPATH) - { - char Background[LC_MAXPATH]; - file->ReadBuffer(Background, sh); - mProperties.mBackgroundImage = Background; - } - else - file->Seek(sh, SEEK_CUR); - } - - if (fv >= 0.8f) - { - file->ReadBuffer(&ch, 1); - file->Seek(ch, SEEK_CUR); - file->ReadBuffer(&ch, 1); - file->Seek(ch, SEEK_CUR); - } - - if (fv > 0.9f) - { - file->ReadU32(&rgb, 1); - mProperties.mAmbientColor[0] = (float)((unsigned char) (rgb))/255; - mProperties.mAmbientColor[1] = (float)((unsigned char) (((unsigned short) (rgb)) >> 8))/255; - mProperties.mAmbientColor[2] = (float)((unsigned char) ((rgb) >> 16))/255; - - if (fv < 1.3f) - file->Seek(23, SEEK_CUR); - else - file->Seek(11, SEEK_CUR); - } - - if (fv > 1.0f) - { - file->ReadU32(&rgb, 1); - mProperties.mBackgroundGradientColor1[0] = (float)((unsigned char) (rgb))/255; - mProperties.mBackgroundGradientColor1[1] = (float)((unsigned char) (((unsigned short) (rgb)) >> 8))/255; - mProperties.mBackgroundGradientColor1[2] = (float)((unsigned char) ((rgb) >> 16))/255; - file->ReadU32(&rgb, 1); - mProperties.mBackgroundGradientColor2[0] = (float)((unsigned char) (rgb))/255; - mProperties.mBackgroundGradientColor2[1] = (float)((unsigned char) (((unsigned short) (rgb)) >> 8))/255; - mProperties.mBackgroundGradientColor2[2] = (float)((unsigned char) ((rgb) >> 16))/255; - } - - UpdateBackgroundTexture(); - CalculateStep(mCurrentStep); - lcGetPiecesLibrary()->UnloadUnusedParts(); - - return true; -} - -void lcModel::Merge(lcModel* Other) -{ - for (int PieceIdx = 0; PieceIdx < Other->mPieces.GetSize(); PieceIdx++) - { - lcPiece* Piece = Other->mPieces[PieceIdx]; - Piece->SetFileLine(-1); - AddPiece(Piece); - } - - Other->mPieces.RemoveAll(); - - for (int CameraIdx = 0; CameraIdx < Other->mCameras.GetSize(); CameraIdx++) - { - lcCamera* Camera = Other->mCameras[CameraIdx]; - Camera->CreateName(mCameras); - mCameras.Add(Camera); - } - - Other->mCameras.RemoveAll(); - - for (int LightIdx = 0; LightIdx < Other->mLights.GetSize(); LightIdx++) - { - lcLight* Light = Other->mLights[LightIdx]; - Light->CreateName(mLights); - mLights.Add(Light); - } - - Other->mLights.RemoveAll(); - - for (int GroupIdx = 0; GroupIdx < Other->mGroups.GetSize(); GroupIdx++) - { - lcGroup* Group = Other->mGroups[GroupIdx]; - Group->CreateName(mGroups); - mGroups.Add(Group); - } - - Other->mGroups.RemoveAll(); - - delete Other; - - gMainWindow->UpdateTimeline(false, false); -} - -void lcModel::Cut() -{ - Copy(); - - if (RemoveSelectedObjects()) - { - gMainWindow->UpdateTimeline(false, false); - gMainWindow->UpdateSelectedObjects(true); - gMainWindow->UpdateAllViews(); - SaveCheckpoint("Cutting"); - } -} - -void lcModel::Copy() -{ - QByteArray File; - QTextStream Stream(&File, QIODevice::WriteOnly); - - SaveLDraw(Stream, true); - - g_App->ExportClipboard(File); -} - -void lcModel::Paste() -{ - if (g_App->mClipboard.isEmpty()) - return; - - lcModel* Model = new lcModel(QString()); - - QBuffer Buffer(&g_App->mClipboard); - Buffer.open(QIODevice::ReadOnly); - Model->LoadLDraw(Buffer, lcGetActiveProject()); - - const lcArray& PastedPieces = Model->mPieces; - lcArray SelectedObjects; - SelectedObjects.AllocGrow(PastedPieces.GetSize()); - - for (int PieceIdx = 0; PieceIdx < PastedPieces.GetSize(); PieceIdx++) - { - lcPiece* Piece = PastedPieces[PieceIdx]; - lcStep Step = Piece->GetStepShow(); - - if (Step > mCurrentStep) - Piece->SetStepShow(mCurrentStep); - - SelectedObjects.Add(Piece); - } - - Merge(Model); - SaveCheckpoint(tr("Pasting")); - - if (PastedPieces.GetSize() == 1) - ClearSelectionAndSetFocus(PastedPieces[0], LC_PIECE_SECTION_POSITION); - else - SetSelectionAndFocus(SelectedObjects, NULL, 0); - - CalculateStep(mCurrentStep); - gMainWindow->UpdateTimeline(false, false); - gMainWindow->UpdateAllViews(); -} - -void lcModel::GetScene(lcScene& Scene, lcCamera* ViewCamera, bool DrawInterface) const -{ - Scene.Begin(ViewCamera->mWorldView); - - mPieceInfo->AddRenderMesh(Scene); - - for (int PieceIdx = 0; PieceIdx < mPieces.GetSize(); PieceIdx++) - { - lcPiece* Piece = mPieces[PieceIdx]; - - if (Piece->IsVisible(mCurrentStep)) - Piece->AddRenderMeshes(Scene, DrawInterface); - } - - if (DrawInterface) - { - for (int CameraIdx = 0; CameraIdx < mCameras.GetSize(); CameraIdx++) - { - lcCamera* Camera = mCameras[CameraIdx]; - - if (Camera != ViewCamera && Camera->IsVisible()) - Scene.mInterfaceObjects.Add(Camera); - } - - for (int LightIdx = 0; LightIdx < mLights.GetSize(); LightIdx++) - { - lcLight* Light = mLights[LightIdx]; - - if (Light->IsVisible()) - Scene.mInterfaceObjects.Add(Light); - } - } - - Scene.End(); -} - -void lcModel::SubModelAddRenderMeshes(lcScene& Scene, const lcMatrix44& WorldMatrix, int DefaultColorIndex, bool Focused, bool Selected) const -{ - for (int PieceIdx = 0; PieceIdx < mPieces.GetSize(); PieceIdx++) - { - lcPiece* Piece = mPieces[PieceIdx]; - - if (Piece->GetStepHide() != LC_STEP_MAX) - continue; - - int ColorIndex = Piece->mColorIndex; - - if (ColorIndex == gDefaultColor) - ColorIndex = DefaultColorIndex; - - PieceInfo* Info = Piece->mPieceInfo; - Info->AddRenderMeshes(Scene, lcMul(Piece->mModelWorld, WorldMatrix), ColorIndex, Focused, Selected); - } -} - -void lcModel::DrawBackground(lcContext* Context) -{ - if (mProperties.mBackgroundType == LC_BACKGROUND_SOLID) - { - glClearColor(mProperties.mBackgroundSolidColor[0], mProperties.mBackgroundSolidColor[1], mProperties.mBackgroundSolidColor[2], 0.0f); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - return; - } - - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - - glDepthMask(GL_FALSE); - glDisable(GL_DEPTH_TEST); - glDisable(GL_LIGHTING); - - float ViewWidth = (float)Context->GetViewportWidth(); - float ViewHeight = (float)Context->GetViewportHeight(); - - Context->SetWorldMatrix(lcMatrix44Identity()); - Context->SetViewMatrix(lcMatrix44Translation(lcVector3(0.375, 0.375, 0.0))); - Context->SetProjectionMatrix(lcMatrix44Ortho(0.0f, ViewWidth, 0.0f, ViewHeight, -1.0f, 1.0f)); - - if (mProperties.mBackgroundType == LC_BACKGROUND_GRADIENT) - { - glShadeModel(GL_SMOOTH); - - const lcVector3& Color1 = mProperties.mBackgroundGradientColor1; - const lcVector3& Color2 = mProperties.mBackgroundGradientColor2; - - float Verts[] = - { - ViewWidth, ViewHeight, Color1[0], Color1[1], Color1[2], 1.0f, - 0.0f, ViewHeight, Color1[0], Color1[1], Color1[2], 1.0f, - 0.0f, 0.0f, Color2[0], Color2[1], Color2[2], 1.0f, - ViewWidth, 0.0f, Color2[0], Color2[1], Color2[2], 1.0f - }; - - Context->SetProgram(LC_PROGRAM_VERTEX_COLOR); - Context->SetVertexBufferPointer(Verts); - Context->SetVertexFormat(0, 2, 0, 4); - - Context->DrawPrimitives(GL_TRIANGLE_FAN, 0, 4); - - Context->ClearVertexBuffer(); // context remove - - glShadeModel(GL_FLAT); - } - else if (mProperties.mBackgroundType == LC_BACKGROUND_IMAGE) - { - glEnable(GL_TEXTURE_2D); - - glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); - glBindTexture(GL_TEXTURE_2D, mBackgroundTexture->mTexture); - - float TileWidth = 1.0f, TileHeight = 1.0f; - - if (mProperties.mBackgroundImageTile) - { - TileWidth = ViewWidth / mBackgroundTexture->mWidth; - TileHeight = ViewHeight / mBackgroundTexture->mHeight; - } - - float Verts[] = - { - 0.0f, ViewHeight, 0.0f, 0.0f, - ViewWidth, ViewHeight, TileWidth, 0.0f, - ViewWidth, 0.0f, TileWidth, TileHeight, - 0.0f, 0.0f, 0.0f, TileHeight - }; - - Context->SetProgram(LC_PROGRAM_TEXTURE); - Context->SetVertexBufferPointer(Verts); - Context->SetVertexFormat(0, 2, 2, 0); - - Context->DrawPrimitives(GL_TRIANGLE_FAN, 0, 4); - - Context->ClearVertexBuffer(); // context remove - - glDisable(GL_TEXTURE_2D); - } - - glEnable(GL_DEPTH_TEST); - glDepthMask(GL_TRUE); -} - -void lcModel::SaveStepImages(const QString& BaseName, int Width, int Height, lcStep Start, lcStep End) -{ - gMainWindow->mPreviewWidget->MakeCurrent(); - lcContext* Context = gMainWindow->mPreviewWidget->mContext; - - if (!Context->BeginRenderToTexture(Width, Height)) - { - QMessageBox::warning(gMainWindow, tr("LeoCAD"), tr("Error creating images.")); - return; - } - - lcStep CurrentStep = mCurrentStep; - - View View(this); - View.SetCamera(gMainWindow->GetActiveView()->mCamera, false); - View.mWidth = Width; - View.mHeight = Height; - View.SetContext(Context); - - for (lcStep Step = Start; Step <= End; Step++) - { - SetTemporaryStep(Step); - View.OnDraw(); - - QString FileName = BaseName.arg(Step, 2, 10, QLatin1Char('0')); - - if (!Context->SaveRenderToTextureImage(FileName, Width, Height)) - break; - } - - Context->EndRenderToTexture(); - - SetTemporaryStep(CurrentStep); - - if (!mActive) - CalculateStep(LC_STEP_MAX); -} - -void lcModel::UpdateBackgroundTexture() -{ - lcReleaseTexture(mBackgroundTexture); - mBackgroundTexture = NULL; - - if (mProperties.mBackgroundType == LC_BACKGROUND_IMAGE) - { - mBackgroundTexture = lcLoadTexture(mProperties.mBackgroundImage, LC_TEXTURE_WRAPU | LC_TEXTURE_WRAPV); - - if (!mBackgroundTexture) - mProperties.mBackgroundType = LC_BACKGROUND_SOLID; - } -} - -void lcModel::RayTest(lcObjectRayTest& ObjectRayTest) const -{ - for (int PieceIdx = 0; PieceIdx < mPieces.GetSize(); PieceIdx++) - { - lcPiece* Piece = mPieces[PieceIdx]; - - if (Piece->IsVisible(mCurrentStep)) - Piece->RayTest(ObjectRayTest); - } - - if (ObjectRayTest.PiecesOnly) - return; - - for (int CameraIdx = 0; CameraIdx < mCameras.GetSize(); CameraIdx++) - { - lcCamera* Camera = mCameras[CameraIdx]; - - if (Camera != ObjectRayTest.ViewCamera && Camera->IsVisible()) - Camera->RayTest(ObjectRayTest); - } - - for (int LightIdx = 0; LightIdx < mLights.GetSize(); LightIdx++) - if (mLights[LightIdx]->IsVisible()) - mLights[LightIdx]->RayTest(ObjectRayTest); -} - -void lcModel::BoxTest(lcObjectBoxTest& ObjectBoxTest) const -{ - for (int PieceIdx = 0; PieceIdx < mPieces.GetSize(); PieceIdx++) - { - lcPiece* Piece = mPieces[PieceIdx]; - - if (Piece->IsVisible(mCurrentStep)) - Piece->BoxTest(ObjectBoxTest); - } - - for (int CameraIdx = 0; CameraIdx < mCameras.GetSize(); CameraIdx++) - { - lcCamera* Camera = mCameras[CameraIdx]; - - if (Camera != ObjectBoxTest.ViewCamera && Camera->IsVisible()) - Camera->BoxTest(ObjectBoxTest); - } - - for (int LightIdx = 0; LightIdx < mLights.GetSize(); LightIdx++) - if (mLights[LightIdx]->IsVisible()) - mLights[LightIdx]->BoxTest(ObjectBoxTest); -} - -bool lcModel::SubModelMinIntersectDist(const lcVector3& WorldStart, const lcVector3& WorldEnd, float& MinDistance) const -{ - bool MinIntersect = false; - - for (int PieceIdx = 0; PieceIdx < mPieces.GetSize(); PieceIdx++) - { - lcPiece* Piece = mPieces[PieceIdx]; - - lcMatrix44 InverseWorldMatrix = lcMatrix44AffineInverse(Piece->mModelWorld); - lcVector3 Start = lcMul31(WorldStart, InverseWorldMatrix); - lcVector3 End = lcMul31(WorldEnd, InverseWorldMatrix); - - if (Piece->GetStepHide() == LC_STEP_MAX && Piece->mPieceInfo->MinIntersectDist(Start, End, MinDistance)) // todo: this should check for piece->mMesh first - MinIntersect = true; - } - - return MinIntersect; -} - -bool lcModel::SubModelBoxTest(const lcVector4 Planes[6]) const -{ - for (int PieceIdx = 0; PieceIdx < mPieces.GetSize(); PieceIdx++) - { - lcPiece* Piece = mPieces[PieceIdx]; - - if (Piece->GetStepHide() != LC_STEP_MAX) - continue; - - if (Piece->mPieceInfo->BoxTest(Piece->mModelWorld, Planes)) - return true; - } - - return false; -} - -void lcModel::SaveCheckpoint(const QString& Description) -{ - lcModelHistoryEntry* ModelHistoryEntry = new lcModelHistoryEntry(); - - ModelHistoryEntry->Description = Description; - - QTextStream Stream(&ModelHistoryEntry->File); - SaveLDraw(Stream, false); - - mUndoHistory.InsertAt(0, ModelHistoryEntry); - mRedoHistory.DeleteAll(); - - if (!Description.isEmpty()) - { - gMainWindow->UpdateModified(IsModified()); - gMainWindow->UpdateUndoRedo(mUndoHistory.GetSize() > 1 ? mUndoHistory[0]->Description : QString(), !mRedoHistory.IsEmpty() ? mRedoHistory[0]->Description : QString()); - } -} - -void lcModel::LoadCheckPoint(lcModelHistoryEntry* CheckPoint) -{ - DeleteModel(); - - QBuffer Buffer(&CheckPoint->File); - Buffer.open(QIODevice::ReadOnly); - LoadLDraw(Buffer, lcGetActiveProject()); - - gMainWindow->UpdateTimeline(true, false); - gMainWindow->UpdateCameraMenu(); - gMainWindow->UpdateCurrentStep(); - gMainWindow->UpdateSelectedObjects(true); - gMainWindow->UpdateAllViews(); -} - -void lcModel::SetActive(bool Active) -{ - if (Active) - { - CalculateStep(mCurrentStep); - } - else - { - CalculateStep(LC_STEP_MAX); - - strncpy(mPieceInfo->m_strName, mProperties.mName.toLatin1().constData(), sizeof(mPieceInfo->m_strName)); - strupr(mPieceInfo->m_strName); - mPieceInfo->m_strName[sizeof(mPieceInfo->m_strName) - 1] = 0; - strncpy(mPieceInfo->m_strDescription, mProperties.mName.toLatin1().constData(), sizeof(mPieceInfo->m_strDescription)); - mPieceInfo->m_strDescription[sizeof(mPieceInfo->m_strDescription) - 1] = 0; - } - - mActive = Active; -} - -void lcModel::CalculateStep(lcStep Step) -{ - for (int PieceIdx = 0; PieceIdx < mPieces.GetSize(); PieceIdx++) - { - lcPiece* Piece = mPieces[PieceIdx]; - Piece->UpdatePosition(Step); - - if (Piece->IsSelected()) - { - if (!Piece->IsVisible(Step)) - Piece->SetSelected(false); - else - SelectGroup(Piece->GetTopGroup(), true); - } - } - - for (int CameraIdx = 0; CameraIdx < mCameras.GetSize(); CameraIdx++) - mCameras[CameraIdx]->UpdatePosition(Step); - - for (int LightIdx = 0; LightIdx < mLights.GetSize(); LightIdx++) - mLights[LightIdx]->UpdatePosition(Step); -} - -void lcModel::SetCurrentStep(lcStep Step) -{ - mCurrentStep = Step; - CalculateStep(Step); - - gMainWindow->UpdateTimeline(false, false); - gMainWindow->UpdateSelectedObjects(true); - gMainWindow->UpdateAllViews(); - gMainWindow->UpdateCurrentStep(); -} - -void lcModel::ShowFirstStep() -{ - if (mCurrentStep == 1) - return; - - SetCurrentStep(1); -} - -void lcModel::ShowLastStep() -{ - lcStep LastStep = GetLastStep(); - - if (mCurrentStep == LastStep) - return; - - SetCurrentStep(LastStep); -} - -void lcModel::ShowPreviousStep() -{ - if (mCurrentStep == 1) - return; - - SetCurrentStep(mCurrentStep - 1); -} - -void lcModel::ShowNextStep() -{ - if (mCurrentStep == LC_STEP_MAX) - return; - - SetCurrentStep(mCurrentStep + 1); -} - -lcStep lcModel::GetLastStep() const -{ - lcStep Step = 1; - - for (int PieceIdx = 0; PieceIdx < mPieces.GetSize(); PieceIdx++) - Step = lcMax(Step, mPieces[PieceIdx]->GetStepShow()); - - return Step; -} - -void lcModel::InsertStep(lcStep Step) -{ - for (int PieceIdx = 0; PieceIdx < mPieces.GetSize(); PieceIdx++) - { - lcPiece* Piece = mPieces[PieceIdx]; - Piece->InsertTime(Step, 1); - if (Piece->IsSelected() && !Piece->IsVisible(mCurrentStep)) - Piece->SetSelected(false); - } - - for (int CameraIdx = 0; CameraIdx < mCameras.GetSize(); CameraIdx++) - mCameras[CameraIdx]->InsertTime(Step, 1); - - for (int LightIdx = 0; LightIdx < mLights.GetSize(); LightIdx++) - mLights[LightIdx]->InsertTime(Step, 1); - - SaveCheckpoint(tr("Inserting Step")); - SetCurrentStep(mCurrentStep); -} - -void lcModel::RemoveStep(lcStep Step) -{ - for (int PieceIdx = 0; PieceIdx < mPieces.GetSize(); PieceIdx++) - { - lcPiece* Piece = mPieces[PieceIdx]; - Piece->RemoveTime(Step, 1); - if (Piece->IsSelected() && !Piece->IsVisible(mCurrentStep)) - Piece->SetSelected(false); - } - - for (int CameraIdx = 0; CameraIdx < mCameras.GetSize(); CameraIdx++) - mCameras[CameraIdx]->RemoveTime(Step, 1); - - for (int LightIdx = 0; LightIdx < mLights.GetSize(); LightIdx++) - mLights[LightIdx]->RemoveTime(Step, 1); - - SaveCheckpoint(tr("Removing Step")); - SetCurrentStep(mCurrentStep); -} - -lcGroup* lcModel::AddGroup(const QString& Prefix, lcGroup* Parent) -{ - lcGroup* Group = new lcGroup(); - mGroups.Add(Group); - - Group->mName = GetGroupName(Prefix); - Group->mGroup = Parent; - - return Group; -} - -lcGroup* lcModel::GetGroup(const QString& Name, bool CreateIfMissing) -{ - for (int GroupIdx = 0; GroupIdx < mGroups.GetSize(); GroupIdx++) - { - lcGroup* Group = mGroups[GroupIdx]; - - if (Group->mName == Name) - return Group; - } - - if (CreateIfMissing) - { - lcGroup* Group = new lcGroup(); - Group->mName = Name; - mGroups.Add(Group); - - return Group; - } - - return NULL; -} - -void lcModel::RemoveGroup(lcGroup* Group) -{ - mGroups.Remove(Group); - delete Group; -} - -void lcModel::GroupSelection() -{ - if (!AnyPiecesSelected()) - { - QMessageBox::information(gMainWindow, tr("LeoCAD"), tr("No pieces selected.")); - return; - } - - lcQGroupDialog Dialog(gMainWindow, GetGroupName(tr("Group #"))); - if (Dialog.exec() != QDialog::Accepted) - return; - - lcGroup* NewGroup = GetGroup(Dialog.mName, true); - - for (int PieceIdx = 0; PieceIdx < mPieces.GetSize(); PieceIdx++) - { - lcPiece* Piece = mPieces[PieceIdx]; - - if (Piece->IsSelected()) - { - lcGroup* Group = Piece->GetTopGroup(); - - if (!Group) - Piece->SetGroup(NewGroup); - else if (Group != NewGroup) - Group->mGroup = NewGroup; - } - } - - SaveCheckpoint(tr("Grouping")); -} - -void lcModel::UngroupSelection() -{ - lcArray SelectedGroups; - - for (int PieceIdx = 0; PieceIdx < mPieces.GetSize(); PieceIdx++) - { - lcPiece* Piece = mPieces[PieceIdx]; - - if (Piece->IsSelected()) - { - lcGroup* Group = Piece->GetTopGroup(); - - if (SelectedGroups.FindIndex(Group) == -1) - { - mGroups.Remove(Group); - SelectedGroups.Add(Group); - } - } - } - - for (int PieceIdx = 0; PieceIdx < mPieces.GetSize(); PieceIdx++) - { - lcPiece* Piece = mPieces[PieceIdx]; - lcGroup* Group = Piece->GetGroup(); - - if (SelectedGroups.FindIndex(Group) != -1) - Piece->SetGroup(NULL); - } - - for (int GroupIdx = 0; GroupIdx < mGroups.GetSize(); GroupIdx++) - { - lcGroup* Group = mGroups[GroupIdx]; - - if (SelectedGroups.FindIndex(Group->mGroup) != -1) - Group->mGroup = NULL; - } - - SelectedGroups.DeleteAll(); - - RemoveEmptyGroups(); - SaveCheckpoint(tr("Ungrouping")); -} - -void lcModel::AddSelectedPiecesToGroup() -{ - lcGroup* Group = NULL; - - for (int PieceIdx = 0; PieceIdx < mPieces.GetSize(); PieceIdx++) - { - lcPiece* Piece = mPieces[PieceIdx]; - - if (Piece->IsSelected()) - { - Group = Piece->GetTopGroup(); - if (Group) - break; - } - } - - if (Group) - { - for (int PieceIdx = 0; PieceIdx < mPieces.GetSize(); PieceIdx++) - { - lcPiece* Piece = mPieces[PieceIdx]; - - if (Piece->IsFocused()) - { - Piece->SetGroup(Group); - break; - } - } - } - - RemoveEmptyGroups(); - SaveCheckpoint(tr("Grouping")); -} - -void lcModel::RemoveFocusPieceFromGroup() -{ - for (int PieceIdx = 0; PieceIdx < mPieces.GetSize(); PieceIdx++) - { - lcPiece* Piece = mPieces[PieceIdx]; - - if (Piece->IsFocused()) - { - Piece->SetGroup(NULL); - break; - } - } - - RemoveEmptyGroups(); - SaveCheckpoint(tr("Ungrouping")); -} - -void lcModel::ShowEditGroupsDialog() -{ - QMap PieceParents; - QMap GroupParents; - - for (int PieceIdx = 0; PieceIdx < mPieces.GetSize(); PieceIdx++) - { - lcPiece* Piece = mPieces[PieceIdx]; - PieceParents[Piece] = Piece->GetGroup(); - } - - for (int GroupIdx = 0; GroupIdx < mGroups.GetSize(); GroupIdx++) - { - lcGroup* Group = mGroups[GroupIdx]; - GroupParents[Group] = Group->mGroup; - } - - lcQEditGroupsDialog Dialog(gMainWindow, PieceParents, GroupParents); - - if (Dialog.exec() != QDialog::Accepted) - return; - - bool Modified = Dialog.mNewGroups.isEmpty(); - - for (int PieceIdx = 0; PieceIdx < mPieces.GetSize(); PieceIdx++) - { - lcPiece* Piece = mPieces[PieceIdx]; - lcGroup* ParentGroup = Dialog.mPieceParents.value(Piece); - - if (ParentGroup != Piece->GetGroup()) - { - mPieces[PieceIdx]->SetGroup(ParentGroup); - Modified = true; - } - } - - for (int GroupIdx = 0; GroupIdx < mGroups.GetSize(); GroupIdx++) - { - lcGroup* Group = mGroups[GroupIdx]; - lcGroup* ParentGroup = Dialog.mGroupParents.value(Group); - - if (ParentGroup != Group->mGroup) - { - Group->mGroup = ParentGroup; - Modified = true; - } - } - - if (Modified) - { - ClearSelection(true); - SaveCheckpoint(tr("Editing Groups")); - } -} - -QString lcModel::GetGroupName(const QString& Prefix) -{ - int Length = Prefix.length(); - int Max = 0; - - for (int GroupIdx = 0; GroupIdx < mGroups.GetSize(); GroupIdx++) - { - const QString& Name = mGroups[GroupIdx]->mName; - - if (Name.startsWith(Prefix)) - { - bool Ok = false; - int GroupNumber = Name.mid(Length).toInt(&Ok); - if (Ok && GroupNumber > Max) - Max = GroupNumber; - } - } - - return Prefix + QString::number(Max + 1); -} - -void lcModel::RemoveEmptyGroups() -{ - bool Removed; - - do - { - Removed = false; - - for (int GroupIdx = 0; GroupIdx < mGroups.GetSize();) - { - lcGroup* Group = mGroups[GroupIdx]; - int Ref = 0; - - for (int PieceIdx = 0; PieceIdx < mPieces.GetSize(); PieceIdx++) - if (mPieces[PieceIdx]->GetGroup() == Group) - Ref++; - - for (int ParentIdx = 0; ParentIdx < mGroups.GetSize(); ParentIdx++) - if (mGroups[ParentIdx]->mGroup == Group) - Ref++; - - if (Ref > 1) - { - GroupIdx++; - continue; - } - - if (Ref != 0) - { - for (int PieceIdx = 0; PieceIdx < mPieces.GetSize(); PieceIdx++) - { - lcPiece* Piece = mPieces[PieceIdx]; - - if (Piece->GetGroup() == Group) - { - Piece->SetGroup(Group->mGroup); - break; - } - } - - for (int ParentIdx = 0; ParentIdx < mGroups.GetSize(); ParentIdx++) - { - if (mGroups[ParentIdx]->mGroup == Group) - { - mGroups[ParentIdx]->mGroup = Group->mGroup; - break; - } - } - } - - mGroups.RemoveIndex(GroupIdx); - delete Group; - Removed = true; - } - } - while (Removed); -} - -lcVector3 lcModel::LockVector(const lcVector3& Vector) const -{ - lcVector3 NewVector(Vector); - - if (gMainWindow->GetLockX()) - NewVector[0] = 0; - - if (gMainWindow->GetLockY()) - NewVector[1] = 0; - - if (gMainWindow->GetLockZ()) - NewVector[2] = 0; - - return NewVector; -} - -lcVector3 lcModel::SnapPosition(const lcVector3& Distance) const -{ - lcVector3 NewDistance(Distance); - - float SnapXY = gMainWindow->GetMoveXYSnap(); - if (SnapXY != 0.0f) - { - int i = (int)(NewDistance[0] / SnapXY); - float Leftover = NewDistance[0] - (SnapXY * i); - - if (Leftover > SnapXY / 2) - { - Leftover -= SnapXY; - i++; - } - else if (Leftover < -SnapXY / 2) - { - Leftover += SnapXY; - i--; - } - - NewDistance[0] = SnapXY * i; - - i = (int)(NewDistance[1] / SnapXY); - Leftover = NewDistance[1] - (SnapXY * i); - - if (Leftover > SnapXY / 2) - { - Leftover -= SnapXY; - i++; - } - else if (Leftover < -SnapXY / 2) - { - Leftover += SnapXY; - i--; - } - - NewDistance[1] = SnapXY * i; - } - - float SnapZ = gMainWindow->GetMoveZSnap(); - if (SnapZ != 0.0f) - { - int i = (int)(NewDistance[2] / SnapZ); - float Leftover = NewDistance[2] - (SnapZ * i); - - if (Leftover > SnapZ / 2) - { - Leftover -= SnapZ; - i++; - } - else if (Leftover < -SnapZ / 2) - { - Leftover += SnapZ; - i--; - } - - NewDistance[2] = SnapZ * i; - } - - return NewDistance; -} - -lcVector3 lcModel::SnapRotation(const lcVector3& Angles) const -{ - int AngleSnap = gMainWindow->GetAngleSnap(); - lcVector3 NewAngles(Angles); - - if (AngleSnap) - { - int Snap[3]; - - for (int i = 0; i < 3; i++) - Snap[i] = (int)(Angles[i] / (float)AngleSnap); - - NewAngles = lcVector3((float)(AngleSnap * Snap[0]), (float)(AngleSnap * Snap[1]), (float)(AngleSnap * Snap[2])); - } - - return NewAngles; -} - -lcMatrix33 lcModel::GetRelativeRotation() const -{ - if (gMainWindow->GetRelativeTransform()) - { - lcObject* Focus = GetFocusObject(); - - if (Focus && Focus->IsPiece()) - return ((lcPiece*)Focus)->GetRelativeRotation(); - } - - return lcMatrix33Identity(); -} - -void lcModel::AddPiece() -{ - PieceInfo* CurPiece = gMainWindow->mPreviewWidget->GetCurrentPiece(); - - if (!CurPiece) - return; - - lcPiece* Last = mPieces.IsEmpty() ? NULL : mPieces[mPieces.GetSize() - 1]; - - for (int PieceIdx = 0; PieceIdx < mPieces.GetSize(); PieceIdx++) - { - lcPiece* Piece = mPieces[PieceIdx]; - - if (Piece->IsFocused()) - { - Last = Piece; - break; - } - } - - lcMatrix44 WorldMatrix; - - if (Last) - { - const lcBoundingBox& BoundingBox = Last->GetBoundingBox(); - lcVector3 Dist(0, 0, BoundingBox.Max.z - BoundingBox.Min.z); - Dist = SnapPosition(Dist); - - WorldMatrix = Last->mModelWorld; - WorldMatrix.SetTranslation(lcMul31(Dist, Last->mModelWorld)); - } - else - { - const lcBoundingBox& BoundingBox = CurPiece->GetBoundingBox(); - WorldMatrix = lcMatrix44Translation(lcVector3(0.0f, 0.0f, -BoundingBox.Min.z)); - } - - lcPiece* Piece = new lcPiece(CurPiece); - Piece->Initialize(WorldMatrix, mCurrentStep); - Piece->SetColorIndex(gMainWindow->mColorIndex); - AddPiece(Piece); - gMainWindow->UpdateTimeline(false, false); - ClearSelectionAndSetFocus(Piece, LC_PIECE_SECTION_POSITION); - - SaveCheckpoint("Adding Piece"); -} - -void lcModel::AddPiece(lcPiece* Piece) -{ - for (int PieceIdx = 0; PieceIdx < mPieces.GetSize(); PieceIdx++) - { - if (mPieces[PieceIdx]->GetStepShow() > Piece->GetStepShow()) - { - InsertPiece(Piece, PieceIdx); - return; - } - } - - InsertPiece(Piece, mPieces.GetSize()); -} - -void lcModel::InsertPiece(lcPiece* Piece, int Index) -{ - PieceInfo* Info = Piece->mPieceInfo; - - if (!Info->IsModel()) - { - lcMesh* Mesh = Info->IsTemporary() ? gPlaceholderMesh : Info->GetMesh(); - - if (Mesh->mVertexCacheOffset == -1) - lcGetPiecesLibrary()->mBuffersDirty = true; - } - - mPieces.InsertAt(Index, Piece); -} - -void lcModel::DeleteAllCameras() -{ - if (mCameras.IsEmpty()) - return; - - mCameras.DeleteAll(); - - gMainWindow->UpdateCameraMenu(); - gMainWindow->UpdateSelectedObjects(true); - gMainWindow->UpdateAllViews(); - SaveCheckpoint("Reseting Cameras"); -} - -void lcModel::DeleteSelectedObjects() -{ - if (RemoveSelectedObjects()) - { - gMainWindow->UpdateTimeline(false, false); - gMainWindow->UpdateSelectedObjects(true); - gMainWindow->UpdateAllViews(); - SaveCheckpoint("Deleting"); - } -} - -void lcModel::ResetSelectedPiecesPivotPoint() -{ - for (int PieceIdx = 0; PieceIdx < mPieces.GetSize(); PieceIdx++) - { - lcPiece* Piece = mPieces[PieceIdx]; - - if (Piece->IsSelected()) - Piece->ResetPivotPoint(); - } - - gMainWindow->UpdateAllViews(); -} - -void lcModel::InsertControlPoint() -{ - lcObject* Focus = GetFocusObject(); - - if (!Focus || !Focus->IsPiece()) - return; - - lcPiece* Piece = (lcPiece*)Focus; - - lcVector3 Start, End; - gMainWindow->GetActiveView()->GetRayUnderPointer(Start, End); - - if (Piece->InsertControlPoint(Start, End)) - { - SaveCheckpoint("Modifying"); - gMainWindow->UpdateSelectedObjects(true); - gMainWindow->UpdateAllViews(); - } -} - -void lcModel::RemoveFocusedControlPoint() -{ - lcObject* Focus = GetFocusObject(); - - if (!Focus || !Focus->IsPiece()) - return; - - lcPiece* Piece = (lcPiece*)Focus; - - if (Piece->RemoveFocusedControlPoint()) - { - SaveCheckpoint("Modifying"); - gMainWindow->UpdateSelectedObjects(true); - gMainWindow->UpdateAllViews(); - } -} - -void lcModel::ShowSelectedPiecesEarlier() -{ - lcArray MovedPieces; - - for (int PieceIdx = 0; PieceIdx < mPieces.GetSize(); ) - { - lcPiece* Piece = mPieces[PieceIdx]; - - if (Piece->IsSelected()) - { - lcStep Step = Piece->GetStepShow(); - - if (Step > 1) - { - Step--; - Piece->SetStepShow(Step); - - MovedPieces.Add(Piece); - mPieces.RemoveIndex(PieceIdx); - continue; - } - } - - PieceIdx++; - } - - if (MovedPieces.IsEmpty()) - return; - - for (int PieceIdx = 0; PieceIdx < MovedPieces.GetSize(); PieceIdx++) - { - lcPiece* Piece = MovedPieces[PieceIdx]; - Piece->SetFileLine(-1); - AddPiece(Piece); - } - - SaveCheckpoint("Modifying"); - gMainWindow->UpdateTimeline(false, false); - gMainWindow->UpdateSelectedObjects(true); - gMainWindow->UpdateAllViews(); -} - -void lcModel::ShowSelectedPiecesLater() -{ - lcArray MovedPieces; - - for (int PieceIdx = 0; PieceIdx < mPieces.GetSize(); ) - { - lcPiece* Piece = mPieces[PieceIdx]; - - if (Piece->IsSelected()) - { - lcStep Step = Piece->GetStepShow(); - - if (Step < LC_STEP_MAX) - { - Step++; - Piece->SetStepShow(Step); - - if (!Piece->IsVisible(mCurrentStep)) - Piece->SetSelected(false); - - MovedPieces.Add(Piece); - mPieces.RemoveIndex(PieceIdx); - continue; - } - } - - PieceIdx++; - } - - if (MovedPieces.IsEmpty()) - return; - - for (int PieceIdx = 0; PieceIdx < MovedPieces.GetSize(); PieceIdx++) - { - lcPiece* Piece = MovedPieces[PieceIdx]; - Piece->SetFileLine(-1); - AddPiece(Piece); - } - - SaveCheckpoint("Modifying"); - gMainWindow->UpdateTimeline(false, false); - gMainWindow->UpdateSelectedObjects(true); - gMainWindow->UpdateAllViews(); -} - -void lcModel::SetPieceSteps(const QList>& PieceSteps) -{ - if (PieceSteps.size() != mPieces.GetSize()) - return; - - bool Modified = false; - - for (int PieceIdx = 0; PieceIdx < PieceSteps.size(); PieceIdx++) - { - const QPair& PieceStep = PieceSteps[PieceIdx]; - lcPiece* Piece = mPieces[PieceIdx]; - - if (Piece != PieceStep.first || Piece->GetStepShow() != PieceStep.second) - { - Piece = PieceStep.first; - lcStep Step = PieceStep.second; - - mPieces[PieceIdx] = Piece; - Piece->SetStepShow(Step); - - if (!Piece->IsVisible(mCurrentStep)) - Piece->SetSelected(false); - - Modified = true; - } - } - - if (Modified) - { - SaveCheckpoint("Modifying"); - gMainWindow->UpdateAllViews(); - gMainWindow->UpdateTimeline(false, false); - gMainWindow->UpdateSelectedObjects(true); - } -} - -void lcModel::MoveSelectionToModel(lcModel* Model) -{ - if (!Model) - return; - - lcArray Pieces; - lcPiece* ModelPiece = NULL; - - for (int PieceIdx = 0; PieceIdx < mPieces.GetSize(); ) - { - lcPiece* Piece = mPieces[PieceIdx]; - - if (Piece->IsSelected()) - { - mPieces.RemoveIndex(PieceIdx); - Piece->SetGroup(NULL); // todo: copy groups - Pieces.Add(Piece); - - if (!ModelPiece) - { - ModelPiece = new lcPiece(Model->mPieceInfo); - ModelPiece->Initialize(lcMatrix44Identity(), Piece->GetStepShow()); - ModelPiece->SetColorIndex(gDefaultColor); - InsertPiece(ModelPiece, PieceIdx); - PieceIdx++; - } - } - else - PieceIdx++; - } - - for (int PieceIdx = 0; PieceIdx < Pieces.GetSize(); PieceIdx++) - Model->AddPiece(Pieces[PieceIdx]); - - lcArray UpdatedModels; - Model->UpdatePieceInfo(UpdatedModels); - ModelPiece->UpdatePosition(mCurrentStep); - - SaveCheckpoint("New Model"); - gMainWindow->UpdateTimeline(false, false); - ClearSelectionAndSetFocus(ModelPiece, LC_PIECE_SECTION_POSITION); -} - -void lcModel::InlineAllModels() -{ - for (;;) - { - bool Inlined = false; - - for (int PieceIdx = 0; PieceIdx < mPieces.GetSize(); ) - { - lcPiece* Piece = mPieces[PieceIdx]; - - if (!Piece->mPieceInfo->IsModel()) - { - PieceIdx++; - continue; - } - - mPieces.RemoveIndex(PieceIdx); - - lcArray ModelParts; - Piece->mPieceInfo->GetModelParts(Piece->mModelWorld, Piece->mColorIndex, ModelParts); - - for (int InsertIdx = 0; InsertIdx < ModelParts.GetSize(); InsertIdx++) - { - lcModelPartsEntry& Entry = ModelParts[InsertIdx]; - - lcPiece* NewPiece = new lcPiece(Entry.Info); - - NewPiece->Initialize(Entry.WorldMatrix, Piece->GetStepShow()); - NewPiece->SetColorIndex(Entry.ColorIndex); - NewPiece->UpdatePosition(mCurrentStep); - - InsertPiece(NewPiece, PieceIdx); - PieceIdx++; - } - - delete Piece; - Inlined = true; - } - - if (!Inlined) - break; - } -} - -void lcModel::InlineSelectedModels() -{ - lcArray NewPieces; - - for (int PieceIdx = 0; PieceIdx < mPieces.GetSize(); ) - { - lcPiece* Piece = mPieces[PieceIdx]; - - if (!Piece->IsSelected() || !Piece->mPieceInfo->IsModel()) - { - PieceIdx++; - continue; - } - - mPieces.RemoveIndex(PieceIdx); - - lcArray ModelParts; - Piece->mPieceInfo->GetModelParts(Piece->mModelWorld, Piece->mColorIndex, ModelParts); - - for (int InsertIdx = 0; InsertIdx < ModelParts.GetSize(); InsertIdx++) - { - lcModelPartsEntry& Entry = ModelParts[InsertIdx]; - - lcPiece* NewPiece = new lcPiece(Entry.Info); - - // todo: recreate in groups in the current model - - NewPiece->Initialize(Entry.WorldMatrix, Piece->GetStepShow()); - NewPiece->SetColorIndex(Entry.ColorIndex); - NewPiece->UpdatePosition(mCurrentStep); - - NewPieces.Add(NewPiece); - InsertPiece(NewPiece, PieceIdx); - PieceIdx++; - } - - delete Piece; - } - - if (!NewPieces.GetSize()) - { - QMessageBox::information(gMainWindow, tr("LeoCAD"), tr("No models selected.")); - return; - } - - SaveCheckpoint("Inlining"); - gMainWindow->UpdateTimeline(false, false); - SetSelectionAndFocus(NewPieces, NULL, 0); -} - -bool lcModel::RemoveSelectedObjects() -{ - bool RemovedPiece = false; - bool RemovedCamera = false; - bool RemovedLight = false; - - for (int PieceIdx = 0; PieceIdx < mPieces.GetSize(); ) - { - lcPiece* Piece = mPieces[PieceIdx]; - - if (Piece->IsSelected()) - { - RemovedPiece = true; - mPieces.Remove(Piece); - delete Piece; - } - else - PieceIdx++; - } - - for (int CameraIdx = 0; CameraIdx < mCameras.GetSize(); ) - { - lcCamera* Camera = mCameras[CameraIdx]; - - if (Camera->IsSelected()) - { - const lcArray* Views = gMainWindow->GetViewsForModel(this); - for (int ViewIdx = 0; ViewIdx < Views->GetSize(); ViewIdx++) - { - View* View = (*Views)[ViewIdx]; - - if (Camera == View->mCamera) - View->SetCamera(Camera, true); - } - - RemovedCamera = true; - mCameras.RemoveIndex(CameraIdx); - delete Camera; - } - else - CameraIdx++; - } - - if (RemovedCamera) - gMainWindow->UpdateCameraMenu(); - - for (int LightIdx = 0; LightIdx < mLights.GetSize(); ) - { - lcLight* Light = mLights[LightIdx]; - - if (Light->IsSelected()) - { - RemovedLight = true; - mLights.RemoveIndex(LightIdx); - delete Light; - } - else - LightIdx++; - } - - RemoveEmptyGroups(); - - return RemovedPiece || RemovedCamera || RemovedLight; -} - -void lcModel::MoveSelectedObjects(const lcVector3& PieceDistance, const lcVector3& ObjectDistance, bool Relative, bool AlternateButtonDrag, bool Update, bool Checkpoint) -{ - bool Moved = false; - lcMatrix33 RelativeRotation; - - if (Relative) - RelativeRotation = GetRelativeRotation(); - else - RelativeRotation = lcMatrix33Identity(); - - if (PieceDistance.LengthSquared() >= 0.001f) - { - lcVector3 TransformedPieceDistance = lcMul(PieceDistance, RelativeRotation); - - if (AlternateButtonDrag) - { - for (int PieceIdx = 0; PieceIdx < mPieces.GetSize(); PieceIdx++) - { - lcPiece* Piece = mPieces[PieceIdx]; - - if (Piece->IsFocused()) - { - Piece->MovePivotPoint(TransformedPieceDistance); - Moved = true; - break; - } - } - } - else - { - for (int PieceIdx = 0; PieceIdx < mPieces.GetSize(); PieceIdx++) - { - lcPiece* Piece = mPieces[PieceIdx]; - - if (Piece->IsSelected()) - { - Piece->Move(mCurrentStep, gMainWindow->GetAddKeys(), TransformedPieceDistance); - Piece->UpdatePosition(mCurrentStep); - Moved = true; - } - } - } - } - - if (ObjectDistance.LengthSquared() >= 0.001f && !AlternateButtonDrag) - { - lcVector3 TransformedObjectDistance = lcMul(ObjectDistance, RelativeRotation); - - for (int CameraIdx = 0; CameraIdx < mCameras.GetSize(); CameraIdx++) - { - lcCamera* Camera = mCameras[CameraIdx]; - - if (Camera->IsSelected()) - { - Camera->Move(mCurrentStep, gMainWindow->GetAddKeys(), TransformedObjectDistance); - Camera->UpdatePosition(mCurrentStep); - Moved = true; - } - } - - for (int LightIdx = 0; LightIdx < mLights.GetSize(); LightIdx++) - { - lcLight* Light = mLights[LightIdx]; - - if (Light->IsSelected()) - { - Light->Move(mCurrentStep, gMainWindow->GetAddKeys(), TransformedObjectDistance); - Light->UpdatePosition(mCurrentStep); - Moved = true; - } - } - } - - if (Moved && Update) - { - gMainWindow->UpdateAllViews(); - if (Checkpoint) - SaveCheckpoint("Moving"); - gMainWindow->UpdateSelectedObjects(false); - } -} - -void lcModel::RotateSelectedPieces(const lcVector3& Angles, bool Relative, bool AlternateButtonDrag, bool Update, bool Checkpoint) -{ - if (Angles.LengthSquared() < 0.001f) - return; - - lcMatrix33 RotationMatrix = lcMatrix33Identity(); - bool Rotated = false; - - if (Angles[0] != 0.0f) - RotationMatrix = lcMul(lcMatrix33RotationX(Angles[0] * LC_DTOR), RotationMatrix); - - if (Angles[1] != 0.0f) - RotationMatrix = lcMul(lcMatrix33RotationY(Angles[1] * LC_DTOR), RotationMatrix); - - if (Angles[2] != 0.0f) - RotationMatrix = lcMul(lcMatrix33RotationZ(Angles[2] * LC_DTOR), RotationMatrix); - - if (AlternateButtonDrag) - { - lcObject* Focus = GetFocusObject(); - - if (Focus && Focus->IsPiece()) - { - ((lcPiece*)Focus)->RotatePivotPoint(RotationMatrix); - Rotated = true; - } - } - else - { - lcVector3 Center; - lcMatrix33 RelativeRotation; - - GetMoveRotateTransform(Center, RelativeRotation); - - lcMatrix33 WorldToFocusMatrix; - - if (Relative) - { - WorldToFocusMatrix = lcMatrix33AffineInverse(RelativeRotation); - RotationMatrix = lcMul(RotationMatrix, RelativeRotation); - } - else - WorldToFocusMatrix = lcMatrix33Identity(); - - for (int PieceIdx = 0; PieceIdx < mPieces.GetSize(); PieceIdx++) - { - lcPiece* Piece = mPieces[PieceIdx]; - - if (!Piece->IsSelected()) - continue; - - Piece->Rotate(mCurrentStep, gMainWindow->GetAddKeys(), RotationMatrix, Center, WorldToFocusMatrix); - Piece->UpdatePosition(mCurrentStep); - Rotated = true; - } - } - - if (Rotated && Update) - { - gMainWindow->UpdateAllViews(); - if (Checkpoint) - SaveCheckpoint("Rotating"); - gMainWindow->UpdateSelectedObjects(false); - } -} - -void lcModel::ScaleSelectedPieces(const float Scale, bool Update, bool Checkpoint) -{ - if (Scale < 0.001f) - return; - - lcObject* Focus = GetFocusObject(); - if (!Focus || !Focus->IsPiece()) - return; - - lcPiece* Piece = (lcPiece*)Focus; - lcuint32 Section = Piece->GetFocusSection(); - - if (Section >= LC_PIECE_SECTION_CONTROL_POINT_1 && Section <= LC_PIECE_SECTION_CONTROL_POINT_8) - { - int ControlPointIndex = Section - LC_PIECE_SECTION_CONTROL_POINT_1; - Piece->SetControlPointScale(ControlPointIndex, Scale); - - if (Update) - { - gMainWindow->UpdateAllViews(); - if (Checkpoint) - SaveCheckpoint("Scaling"); - gMainWindow->UpdateSelectedObjects(false); - } - } -} - -void lcModel::TransformSelectedObjects(lcTransformType TransformType, const lcVector3& Transform) -{ - switch (TransformType) - { - case LC_TRANSFORM_ABSOLUTE_TRANSLATION: - MoveSelectedObjects(Transform, false, false, true, true); - break; - - case LC_TRANSFORM_RELATIVE_TRANSLATION: - MoveSelectedObjects(Transform, true, false, true, true); - break; - - case LC_TRANSFORM_ABSOLUTE_ROTATION: - RotateSelectedPieces(Transform, false, false, true, true); - break; - - case LC_TRANSFORM_RELATIVE_ROTATION: - RotateSelectedPieces(Transform, true, false, true, true); - break; - } -} - -void lcModel::SetSelectedPiecesColorIndex(int ColorIndex) -{ - bool Modified = false; - - for (int PieceIdx = 0; PieceIdx < mPieces.GetSize(); PieceIdx++) - { - lcPiece* Piece = mPieces[PieceIdx]; - - if (Piece->IsSelected() && Piece->mColorIndex != ColorIndex) - { - Piece->SetColorIndex(ColorIndex); - Modified = true; - } - } - - if (Modified) - { - SaveCheckpoint(tr("Painting")); - gMainWindow->UpdateSelectedObjects(false); - gMainWindow->UpdateAllViews(); - gMainWindow->UpdateTimeline(false, true); - } -} - -void lcModel::SetSelectedPiecesPieceInfo(PieceInfo* Info) -{ - bool Modified = false; - - for (int PieceIdx = 0; PieceIdx < mPieces.GetSize(); PieceIdx++) - { - lcPiece* Piece = mPieces[PieceIdx]; - - if (Piece->IsSelected() && Piece->mPieceInfo != Info) - { - Piece->mPieceInfo->Release(true); - Piece->SetPieceInfo(Info); - Modified = true; - } - } - - if (Modified) - { - SaveCheckpoint(tr("Setting Part")); - gMainWindow->UpdateSelectedObjects(false); - gMainWindow->UpdateAllViews(); - gMainWindow->UpdateTimeline(false, true); - } -} - -void lcModel::SetSelectedPiecesStepShow(lcStep Step) -{ - bool Modified = false; - bool SelectionChanged = false; - - for (int PieceIdx = 0; PieceIdx < mPieces.GetSize(); PieceIdx++) - { - lcPiece* Piece = mPieces[PieceIdx]; - - if (Piece->IsSelected() && Piece->GetStepShow() != Step) - { - Piece->SetStepShow(Step); - - if (!Piece->IsVisible(mCurrentStep)) - { - Piece->SetSelected(false); - SelectionChanged = true; - } - - Modified = true; - } - } - - if (Modified) - { - SaveCheckpoint(tr("Showing Pieces")); - gMainWindow->UpdateAllViews(); - gMainWindow->UpdateTimeline(false, false); - gMainWindow->UpdateSelectedObjects(SelectionChanged); - } -} - -void lcModel::SetSelectedPiecesStepHide(lcStep Step) -{ - bool Modified = false; - bool SelectionChanged = false; - - for (int PieceIdx = 0; PieceIdx < mPieces.GetSize(); PieceIdx++) - { - lcPiece* Piece = mPieces[PieceIdx]; - - if (Piece->IsSelected() && Piece->GetStepHide() != Step) - { - Piece->SetStepHide(Step); - - if (!Piece->IsVisible(mCurrentStep)) - { - Piece->SetSelected(false); - SelectionChanged = true; - } - - Modified = true; - } - } - - if (Modified) - { - SaveCheckpoint(tr("Hiding Pieces")); - gMainWindow->UpdateAllViews(); - gMainWindow->UpdateTimeline(false, false); - gMainWindow->UpdateSelectedObjects(SelectionChanged); - } -} - -void lcModel::SetCameraOrthographic(lcCamera* Camera, bool Ortho) -{ - if (Camera->IsOrtho() == Ortho) - return; - - Camera->SetOrtho(Ortho); - Camera->UpdatePosition(mCurrentStep); - - SaveCheckpoint(tr("Editing Camera")); - gMainWindow->UpdateAllViews(); - gMainWindow->UpdatePerspective(); -} - -void lcModel::SetCameraFOV(lcCamera* Camera, float FOV) -{ - if (Camera->m_fovy == FOV) - return; - - Camera->m_fovy = FOV; - Camera->UpdatePosition(mCurrentStep); - - SaveCheckpoint(tr("Changing FOV")); - gMainWindow->UpdateAllViews(); -} - -void lcModel::SetCameraZNear(lcCamera* Camera, float ZNear) -{ - if (Camera->m_zNear == ZNear) - return; - - Camera->m_zNear = ZNear; - Camera->UpdatePosition(mCurrentStep); - - SaveCheckpoint(tr("Editing Camera")); - gMainWindow->UpdateAllViews(); -} - -void lcModel::SetCameraZFar(lcCamera* Camera, float ZFar) -{ - if (Camera->m_zFar == ZFar) - return; - - Camera->m_zFar = ZFar; - Camera->UpdatePosition(mCurrentStep); - - SaveCheckpoint(tr("Editing Camera")); - gMainWindow->UpdateAllViews(); -} - -void lcModel::SetCameraName(lcCamera* Camera, const char* Name) -{ - if (!strcmp(Camera->m_strName, Name)) - return; - - strncpy(Camera->m_strName, Name, sizeof(Camera->m_strName)); - Camera->m_strName[sizeof(Camera->m_strName) - 1] = 0; - - SaveCheckpoint(tr("Renaming Camera")); - gMainWindow->UpdateSelectedObjects(false); - gMainWindow->UpdateAllViews(); - gMainWindow->UpdateCameraMenu(); -} - -bool lcModel::AnyPiecesSelected() const -{ - for (int PieceIdx = 0; PieceIdx < mPieces.GetSize(); PieceIdx++) - if (mPieces[PieceIdx]->IsSelected()) - return true; - - return false; -} - -bool lcModel::AnyObjectsSelected() const -{ - for (int PieceIdx = 0; PieceIdx < mPieces.GetSize(); PieceIdx++) - if (mPieces[PieceIdx]->IsSelected()) - return true; - - for (int CameraIdx = 0; CameraIdx < mCameras.GetSize(); CameraIdx++) - if (mCameras[CameraIdx]->IsSelected()) - return true; - - for (int LightIdx = 0; LightIdx < mLights.GetSize(); LightIdx++) - if (mLights[LightIdx]->IsSelected()) - return true; - - return false; -} - -lcObject* lcModel::GetFocusObject() const -{ - for (int PieceIdx = 0; PieceIdx < mPieces.GetSize(); PieceIdx++) - { - lcPiece* Piece = mPieces[PieceIdx]; - - if (Piece->IsFocused()) - return Piece; - } - - for (int CameraIdx = 0; CameraIdx < mCameras.GetSize(); CameraIdx++) - { - lcCamera* Camera = mCameras[CameraIdx]; - - if (Camera->IsFocused()) - return Camera; - } - - for (int LightIdx = 0; LightIdx < mLights.GetSize(); LightIdx++) - { - lcLight* Light = mLights[LightIdx]; - - if (Light->IsFocused()) - return Light; - } - - return NULL; -} - -lcModel* lcModel::GetFirstSelectedSubmodel() const -{ - for (int PieceIdx = 0; PieceIdx < mPieces.GetSize(); PieceIdx++) - { - lcPiece* Piece = mPieces[PieceIdx]; - - if (Piece->IsSelected() && Piece->mPieceInfo->IsModel()) - return Piece->mPieceInfo->GetModel(); - } - - return NULL; -} - -void lcModel::GetSubModels(lcArray SubModels) const -{ - for (int PieceIdx = 0; PieceIdx < mPieces.GetSize(); PieceIdx++) - { - lcPiece* Piece = mPieces[PieceIdx]; - - if (Piece->mPieceInfo->IsModel()) - { - lcModel* SubModel = Piece->mPieceInfo->GetModel(); - if (SubModels.FindIndex(SubModel) != -1) - SubModels.Add(SubModel); - } - } -} - -bool lcModel::GetMoveRotateTransform(lcVector3& Center, lcMatrix33& RelativeRotation) const -{ - bool Relative = gMainWindow->GetRelativeTransform(); - int NumSelected = 0; - - Center = lcVector3(0.0f, 0.0f, 0.0f); - RelativeRotation = lcMatrix33Identity(); - - for (int PieceIdx = 0; PieceIdx < mPieces.GetSize(); PieceIdx++) - { - lcPiece* Piece = mPieces[PieceIdx]; - - if (!Piece->IsSelected()) - continue; - - if (Piece->IsFocused() && Relative) - { - Center = Piece->GetRotationCenter(); - RelativeRotation = Piece->GetRelativeRotation(); - return true; - } - - Center += Piece->mModelWorld.GetTranslation(); - NumSelected++; - } - - for (int CameraIdx = 0; CameraIdx < mCameras.GetSize(); CameraIdx++) - { - lcCamera* Camera = mCameras[CameraIdx]; - - if (!Camera->IsSelected()) - continue; - - if (Camera->IsFocused() && Relative) - { - Center = Camera->GetSectionPosition(Camera->GetFocusSection()); -// RelativeRotation = Piece->GetRelativeRotation(); - return true; - } - - Center += Camera->GetSectionPosition(LC_CAMERA_SECTION_POSITION); - Center += Camera->GetSectionPosition(LC_CAMERA_SECTION_TARGET); - Center += Camera->GetSectionPosition(LC_CAMERA_SECTION_UPVECTOR); - NumSelected += 3; - } - - for (int LightIdx = 0; LightIdx < mLights.GetSize(); LightIdx++) - { - lcLight* Light = mLights[LightIdx]; - - if (!Light->IsSelected()) - continue; - - if (Light->IsFocused() && Relative) - { - Center = Light->GetSectionPosition(Light->GetFocusSection()); -// RelativeRotation = Piece->GetRelativeRotation(); - return true; - } - - Center += Light->GetSectionPosition(LC_LIGHT_SECTION_POSITION); - NumSelected++; - if (Light->IsSpotLight() || Light->IsDirectionalLight()) - { - Center += Light->GetSectionPosition(LC_LIGHT_SECTION_TARGET); - NumSelected++; - } - } - - if (NumSelected) - { - Center /= NumSelected; - return true; - } - - return false; -} - -bool lcModel::GetPieceFocusOrSelectionCenter(lcVector3& Center) const -{ - lcVector3 Min(FLT_MAX, FLT_MAX, FLT_MAX), Max(-FLT_MAX, -FLT_MAX, -FLT_MAX); - lcPiece* Selected = NULL; - int NumSelected = 0; - - for (int PieceIdx = 0; PieceIdx < mPieces.GetSize(); PieceIdx++) - { - lcPiece* Piece = mPieces[PieceIdx]; - - if (Piece->IsFocused()) - { - Center = Piece->mModelWorld.GetTranslation(); - return true; - } - - if (Piece->IsSelected()) - { - Piece->CompareBoundingBox(Min, Max); - Selected = Piece; - NumSelected++; - } - } - - if (NumSelected == 1) - Center = Selected->mModelWorld.GetTranslation(); - else if (NumSelected) - Center = (Min + Max) / 2.0f; - else - Center = lcVector3(0.0f, 0.0f, 0.0f); - - return NumSelected != 0; -} - -lcVector3 lcModel::GetSelectionOrModelCenter() const -{ - lcVector3 Center; - - if (!GetSelectionCenter(Center)) - { - lcVector3 Min(FLT_MAX, FLT_MAX, FLT_MAX), Max(-FLT_MAX, -FLT_MAX, -FLT_MAX); - - if (GetPiecesBoundingBox(Min, Max)) - Center = (Min + Max) / 2.0f; - else - Center = lcVector3(0.0f, 0.0f, 0.0f); - } - - return Center; -} - -bool lcModel::GetFocusPosition(lcVector3& Position) const -{ - lcObject* FocusObject = GetFocusObject(); - - if (FocusObject) - { - Position = FocusObject->GetSectionPosition(FocusObject->GetFocusSection()); - return true; - } - else - { - Position = lcVector3(0.0f, 0.0f, 0.0f); - return false; - } -} - -bool lcModel::GetSelectionCenter(lcVector3& Center) const -{ - lcVector3 Min(FLT_MAX, FLT_MAX, FLT_MAX), Max(-FLT_MAX, -FLT_MAX, -FLT_MAX); - lcPiece* SelectedPiece = NULL; - bool SinglePieceSelected = true; - bool Selected = false; - - for (int PieceIdx = 0; PieceIdx < mPieces.GetSize(); PieceIdx++) - { - lcPiece* Piece = mPieces[PieceIdx]; - - if (Piece->IsSelected()) - { - Piece->CompareBoundingBox(Min, Max); - Selected = true; - - if (!SelectedPiece) - SelectedPiece = Piece; - else - SinglePieceSelected = false; - } - } - - for (int CameraIdx = 0; CameraIdx < mCameras.GetSize(); CameraIdx++) - { - lcCamera* Camera = mCameras[CameraIdx]; - - if (Camera->IsSelected()) - { - Camera->CompareBoundingBox(Min, Max); - Selected = true; - SinglePieceSelected = false; - } - } - - for (int LightIdx = 0; LightIdx < mLights.GetSize(); LightIdx++) - { - lcLight* Light = mLights[LightIdx]; - - if (Light->IsSelected()) - { - Light->CompareBoundingBox(Min, Max); - Selected = true; - SinglePieceSelected = false; - } - } - - if (SelectedPiece && SinglePieceSelected) - Center = SelectedPiece->GetSectionPosition(LC_PIECE_SECTION_POSITION); - else if (Selected) - Center = (Min + Max) / 2.0f; - else - Center = lcVector3(0.0f, 0.0f, 0.0f); - - return Selected; -} - -bool lcModel::GetPiecesBoundingBox(lcVector3& Min, lcVector3& Max) const -{ - Min = lcVector3(FLT_MAX, FLT_MAX, FLT_MAX); - Max = lcVector3(-FLT_MAX, -FLT_MAX, -FLT_MAX); - - if (mPieces.IsEmpty()) - return false; - - for (int PieceIdx = 0; PieceIdx < mPieces.GetSize(); PieceIdx++) - { - lcPiece* Piece = mPieces[PieceIdx]; - - if (Piece->IsVisible(mCurrentStep)) - Piece->CompareBoundingBox(Min, Max); - } - - return true; -} - -void lcModel::GetPartsList(int DefaultColorIndex, lcArray& PartsList) const -{ - for (int PieceIdx = 0; PieceIdx < mPieces.GetSize(); PieceIdx++) - { - lcPiece* Piece = mPieces[PieceIdx]; - - int ColorIndex = Piece->mColorIndex; - - if (ColorIndex == gDefaultColor) - ColorIndex = DefaultColorIndex; - - int UsedIdx; - - for (UsedIdx = 0; UsedIdx < PartsList.GetSize(); UsedIdx++) - { - if (PartsList[UsedIdx].Info != Piece->mPieceInfo || PartsList[UsedIdx].ColorIndex != ColorIndex) - continue; - - PartsList[UsedIdx].Count++; - break; - } - - if (UsedIdx == PartsList.GetSize()) - Piece->mPieceInfo->GetPartsList(ColorIndex, PartsList); - } -} - -void lcModel::GetPartsListForStep(lcStep Step, int DefaultColorIndex, lcArray& PartsList) const -{ - for (int PieceIdx = 0; PieceIdx < mPieces.GetSize(); PieceIdx++) - { - lcPiece* Piece = mPieces[PieceIdx]; - - if (Piece->GetStepShow() != Step) - continue; - - int ColorIndex = Piece->mColorIndex; - - if (ColorIndex == gDefaultColor) - ColorIndex = DefaultColorIndex; - - int UsedIdx; - - for (UsedIdx = 0; UsedIdx < PartsList.GetSize(); UsedIdx++) - { - if (PartsList[UsedIdx].Info != Piece->mPieceInfo || PartsList[UsedIdx].ColorIndex != ColorIndex) - continue; - - PartsList[UsedIdx].Count++; - break; - } - - if (UsedIdx == PartsList.GetSize()) - Piece->mPieceInfo->GetPartsList(ColorIndex, PartsList); - } -} - -void lcModel::GetModelParts(const lcMatrix44& WorldMatrix, int DefaultColorIndex, lcArray& ModelParts) const -{ - for (int PieceIdx = 0; PieceIdx < mPieces.GetSize(); PieceIdx++) - { - lcPiece* Piece = mPieces[PieceIdx]; - - int ColorIndex = Piece->mColorIndex; - - if (ColorIndex == gDefaultColor) - ColorIndex = DefaultColorIndex; - - Piece->mPieceInfo->GetModelParts(lcMul(Piece->mModelWorld, WorldMatrix), ColorIndex, ModelParts); - } -} - -void lcModel::GetSelectionInformation(int* Flags, lcArray& Selection, lcObject** Focus) const -{ - *Flags = 0; - *Focus = NULL; - - if (mPieces.IsEmpty()) - *Flags |= LC_SEL_NO_PIECES; - else - { - lcGroup* Group = NULL; - bool First = true; - - for (int PieceIdx = 0; PieceIdx < mPieces.GetSize(); PieceIdx++) - { - lcPiece* Piece = mPieces[PieceIdx]; - - if (Piece->IsSelected()) - { - Selection.Add(Piece); - - if (Piece->IsFocused()) - *Focus = Piece; - - if (Piece->mPieceInfo->IsModel()) - *Flags |= LC_SEL_MODEL_SELECTED; - - if (Piece->IsHidden()) - *Flags |= LC_SEL_HIDDEN | LC_SEL_HIDDEN_SELECTED; - else - *Flags |= LC_SEL_VISIBLE_SELECTED; - - *Flags |= LC_SEL_PIECE | LC_SEL_SELECTED; - - lcSynthInfo* SynthInfo = Piece->mPieceInfo->GetSynthInfo(); - if (SynthInfo && SynthInfo->CanAddControlPoints()) - { - *Flags |= LC_SEL_CAN_ADD_CONTROL_POINT; - - lcuint32 Section = Piece->GetFocusSection(); - - if (Section >= LC_PIECE_SECTION_CONTROL_POINT_1 && Section <= LC_PIECE_SECTION_CONTROL_POINT_8 && Piece->GetControlPoints().GetSize() > 2) - *Flags |= LC_SEL_CAN_REMOVE_CONTROL_POINT; - } - - if (Piece->GetGroup() != NULL) - { - *Flags |= LC_SEL_GROUPED; - if (Piece->IsFocused()) - *Flags |= LC_SEL_FOCUS_GROUPED; - } - - if (First) - { - Group = Piece->GetGroup(); - First = false; - } - else - { - if (Group != Piece->GetGroup()) - *Flags |= LC_SEL_CAN_GROUP; - else - if (Group == NULL) - *Flags |= LC_SEL_CAN_GROUP; - } - } - else - { - *Flags |= LC_SEL_UNSELECTED; - - if (Piece->IsHidden()) - *Flags |= LC_SEL_HIDDEN; - } - } - } - - for (int CameraIdx = 0; CameraIdx < mCameras.GetSize(); CameraIdx++) - { - lcCamera* Camera = mCameras[CameraIdx]; - - if (Camera->IsSelected()) - { - Selection.Add(Camera); - *Flags |= LC_SEL_SELECTED; - - if (Camera->IsFocused()) - *Focus = Camera; - } - } - - for (int LightIdx = 0; LightIdx < mLights.GetSize(); LightIdx++) - { - lcLight* Light = mLights[LightIdx]; - - if (Light->IsSelected()) - { - Selection.Add(Light); - *Flags |= LC_SEL_SELECTED; - - if (Light->IsFocused()) - *Focus = Light; - } - } -} - -void lcModel::ClearSelection(bool UpdateInterface) -{ - for (int PieceIdx = 0; PieceIdx < mPieces.GetSize(); PieceIdx++) - mPieces[PieceIdx]->SetSelected(false); - - for (int CameraIdx = 0; CameraIdx < mCameras.GetSize(); CameraIdx++) - mCameras[CameraIdx]->SetSelected(false); - - for (int LightIdx = 0; LightIdx < mLights.GetSize(); LightIdx++) - mLights[LightIdx]->SetSelected(false); - - if (UpdateInterface) - { - gMainWindow->UpdateSelectedObjects(true); - gMainWindow->UpdateAllViews(); - } -} - -void lcModel::SelectGroup(lcGroup* TopGroup, bool Select) -{ - if (!TopGroup) - return; - - for (int PieceIdx = 0; PieceIdx < mPieces.GetSize(); PieceIdx++) - { - lcPiece* Piece = mPieces[PieceIdx]; - - if (!Piece->IsSelected() && Piece->IsVisible(mCurrentStep) && (Piece->GetTopGroup() == TopGroup)) - Piece->SetSelected(Select); - } -} - -void lcModel::FocusOrDeselectObject(const lcObjectSection& ObjectSection) -{ - lcObject* FocusObject = GetFocusObject(); - lcObject* Object = ObjectSection.Object; - lcuint32 Section = ObjectSection.Section; - - if (Object) - { - bool WasSelected = Object->IsSelected(); - - if (!Object->IsFocused(Section)) - { - if (FocusObject) - FocusObject->SetFocused(FocusObject->GetFocusSection(), false); - - Object->SetFocused(Section, true); - } - else - Object->SetSelected(Section, false); - - bool IsSelected = Object->IsSelected(); - - if (Object->IsPiece() && (WasSelected != IsSelected)) - SelectGroup(((lcPiece*)Object)->GetTopGroup(), IsSelected); - } - else - { - if (FocusObject) - FocusObject->SetFocused(FocusObject->GetFocusSection(), false); - } - - gMainWindow->UpdateSelectedObjects(true); - gMainWindow->UpdateAllViews(); -} - -void lcModel::ClearSelectionAndSetFocus(lcObject* Object, lcuint32 Section) -{ - ClearSelection(false); - - if (Object) - { - Object->SetFocused(Section, true); - - if (Object->IsPiece()) - SelectGroup(((lcPiece*)Object)->GetTopGroup(), true); - } - - gMainWindow->UpdateSelectedObjects(true); - gMainWindow->UpdateAllViews(); -} - -void lcModel::ClearSelectionAndSetFocus(const lcObjectSection& ObjectSection) -{ - ClearSelectionAndSetFocus(ObjectSection.Object, ObjectSection.Section); -} - -void lcModel::SetSelectionAndFocus(const lcArray& Selection, lcObject* Focus, lcuint32 Section) -{ - ClearSelection(false); - - if (Focus) - { - Focus->SetFocused(Section, true); - - if (Focus->IsPiece()) - SelectGroup(((lcPiece*)Focus)->GetTopGroup(), true); - } - - AddToSelection(Selection); -} - -void lcModel::AddToSelection(const lcArray& Objects) -{ - for (int ObjectIdx = 0; ObjectIdx < Objects.GetSize(); ObjectIdx++) - { - lcObject* Object = Objects[ObjectIdx]; - - bool WasSelected = Object->IsSelected(); - Object->SetSelected(Objects[ObjectIdx]); - - if (!WasSelected && Object->GetType() == LC_OBJECT_PIECE) - SelectGroup(((lcPiece*)Object)->GetTopGroup(), true); - } - - gMainWindow->UpdateSelectedObjects(true); - gMainWindow->UpdateAllViews(); -} - -void lcModel::SelectAllPieces() -{ - for (int PieceIdx = 0; PieceIdx < mPieces.GetSize(); PieceIdx++) - { - lcPiece* Piece = mPieces[PieceIdx]; - - if (Piece->IsVisible(mCurrentStep)) - Piece->SetSelected(true); - } - - gMainWindow->UpdateSelectedObjects(true); - gMainWindow->UpdateAllViews(); -} - -void lcModel::InvertSelection() -{ - for (int PieceIdx = 0; PieceIdx < mPieces.GetSize(); PieceIdx++) - { - lcPiece* Piece = mPieces[PieceIdx]; - - if (Piece->IsVisible(mCurrentStep)) - Piece->SetSelected(!Piece->IsSelected()); - } - - gMainWindow->UpdateSelectedObjects(true); - gMainWindow->UpdateAllViews(); -} - -void lcModel::HideSelectedPieces() -{ - for (int PieceIdx = 0; PieceIdx < mPieces.GetSize(); PieceIdx++) - { - lcPiece* Piece = mPieces[PieceIdx]; - - if (Piece->IsSelected()) - { - Piece->SetHidden(true); - Piece->SetSelected(false); - } - } - - gMainWindow->UpdateTimeline(false, true); - gMainWindow->UpdateSelectedObjects(true); - gMainWindow->UpdateAllViews(); -} - -void lcModel::HideUnselectedPieces() -{ - for (int PieceIdx = 0; PieceIdx < mPieces.GetSize(); PieceIdx++) - { - lcPiece* Piece = mPieces[PieceIdx]; - - if (!Piece->IsSelected()) - Piece->SetHidden(true); - } - - gMainWindow->UpdateTimeline(false, true); - gMainWindow->UpdateSelectedObjects(true); - gMainWindow->UpdateAllViews(); -} - -void lcModel::UnhideSelectedPieces() -{ - for (int PieceIdx = 0; PieceIdx < mPieces.GetSize(); PieceIdx++) - { - lcPiece* Piece = mPieces[PieceIdx]; - - if (Piece->IsSelected()) - Piece->SetHidden(false); - } - - gMainWindow->UpdateTimeline(false, true); - gMainWindow->UpdateSelectedObjects(true); - gMainWindow->UpdateAllViews(); -} - -void lcModel::UnhideAllPieces() -{ - for (int PieceIdx = 0; PieceIdx < mPieces.GetSize(); PieceIdx++) - mPieces[PieceIdx]->SetHidden(false); - - gMainWindow->UpdateTimeline(false, true); - gMainWindow->UpdateSelectedObjects(true); - gMainWindow->UpdateAllViews(); -} - -void lcModel::FindPiece(bool FindFirst, bool SearchForward) -{ - if (mPieces.IsEmpty()) - return; - - int StartIdx = mPieces.GetSize() - 1; - if (!FindFirst) - { - for (int PieceIdx = 0; PieceIdx < mPieces.GetSize(); PieceIdx++) - { - lcPiece* Piece = mPieces[PieceIdx]; - - if (Piece->IsFocused() && Piece->IsVisible(mCurrentStep)) - { - StartIdx = PieceIdx; - break; - } - } - } - - int CurrentIdx = StartIdx; - lcObject* Focus = NULL; - const lcSearchOptions& SearchOptions = gMainWindow->mSearchOptions; - - for (;;) - { - if (SearchForward) - CurrentIdx++; - else - CurrentIdx--; - - if (CurrentIdx < 0) - CurrentIdx = mPieces.GetSize() - 1; - else if (CurrentIdx >= mPieces.GetSize()) - CurrentIdx = 0; - - if (CurrentIdx == StartIdx) - break; - - lcPiece* Current = mPieces[CurrentIdx]; - - if (!Current->IsVisible(mCurrentStep)) - continue; - - if ((!SearchOptions.MatchInfo || Current->mPieceInfo == SearchOptions.Info) && - (!SearchOptions.MatchColor || Current->mColorIndex == SearchOptions.ColorIndex) && - (!SearchOptions.MatchName || strcasestr(Current->GetName(), SearchOptions.Name))) - { - Focus = Current; - break; - } - } - - ClearSelectionAndSetFocus(Focus, LC_PIECE_SECTION_POSITION); -} - -void lcModel::UndoAction() -{ - if (mUndoHistory.GetSize() < 2) - return; - - lcModelHistoryEntry* Undo = mUndoHistory[0]; - mUndoHistory.RemoveIndex(0); - mRedoHistory.InsertAt(0, Undo); - - LoadCheckPoint(mUndoHistory[0]); - - gMainWindow->UpdateModified(IsModified()); - gMainWindow->UpdateUndoRedo(mUndoHistory.GetSize() > 1 ? mUndoHistory[0]->Description : NULL, !mRedoHistory.IsEmpty() ? mRedoHistory[0]->Description : NULL); -} - -void lcModel::RedoAction() -{ - if (mRedoHistory.IsEmpty()) - return; - - lcModelHistoryEntry* Redo = mRedoHistory[0]; - mRedoHistory.RemoveIndex(0); - mUndoHistory.InsertAt(0, Redo); - - LoadCheckPoint(Redo); - - gMainWindow->UpdateModified(IsModified()); - gMainWindow->UpdateUndoRedo(mUndoHistory.GetSize() > 1 ? mUndoHistory[0]->Description : NULL, !mRedoHistory.IsEmpty() ? mRedoHistory[0]->Description : NULL); -} - -void lcModel::BeginMouseTool() -{ - mMouseToolDistance = lcVector3(0.0f, 0.0f, 0.0f); -} - -void lcModel::EndMouseTool(lcTool Tool, bool Accept) -{ - if (!Accept) - { - LoadCheckPoint(mUndoHistory[0]); - return; - } - - switch (Tool) - { - case LC_TOOL_INSERT: - case LC_TOOL_LIGHT: - break; - - case LC_TOOL_SPOTLIGHT: - SaveCheckpoint(tr("New SpotLight")); - break; - - case LC_TOOL_CAMERA: - gMainWindow->UpdateCameraMenu(); - SaveCheckpoint(tr("New Camera")); - break; - - case LC_TOOL_SELECT: - break; - - case LC_TOOL_MOVE: - SaveCheckpoint(tr("Move")); - break; - - case LC_TOOL_ROTATE: - SaveCheckpoint(tr("Rotate")); - break; - - case LC_TOOL_ERASER: - case LC_TOOL_PAINT: - break; - - case LC_TOOL_ZOOM: - if (!gMainWindow->GetActiveView()->mCamera->IsSimple()) - SaveCheckpoint(tr("Zoom")); - break; - - case LC_TOOL_PAN: - if (!gMainWindow->GetActiveView()->mCamera->IsSimple()) - SaveCheckpoint(tr("Pan")); - break; - - case LC_TOOL_ROTATE_VIEW: - if (!gMainWindow->GetActiveView()->mCamera->IsSimple()) - SaveCheckpoint(tr("Orbit")); - break; - - case LC_TOOL_ROLL: - if (!gMainWindow->GetActiveView()->mCamera->IsSimple()) - SaveCheckpoint(tr("Roll")); - break; - - case LC_TOOL_ZOOM_REGION: - break; - - case LC_NUM_TOOLS: - break; - } -} - -void lcModel::InsertPieceToolClicked(const lcMatrix44& WorldMatrix) -{ - lcPiece* Piece = new lcPiece(gMainWindow->mPreviewWidget->GetCurrentPiece()); - Piece->Initialize(WorldMatrix, mCurrentStep); - Piece->SetColorIndex(gMainWindow->mColorIndex); - Piece->UpdatePosition(mCurrentStep); - AddPiece(Piece); - - gMainWindow->UpdateTimeline(false, false); - ClearSelectionAndSetFocus(Piece, LC_PIECE_SECTION_POSITION); - - SaveCheckpoint(tr("Insert")); -} - -void lcModel::PointLightToolClicked(const lcVector3& Position) -{ - lcLight* Light = new lcLight(Position[0], Position[1], Position[2]); - Light->CreateName(mLights); - mLights.Add(Light); - - ClearSelectionAndSetFocus(Light, LC_LIGHT_SECTION_POSITION); - SaveCheckpoint(tr("New Light")); -} - -void lcModel::BeginSpotLightTool(const lcVector3& Position, const lcVector3& Target) -{ - lcLight* Light = new lcLight(Position[0], Position[1], Position[2], Target[0], Target[1], Target[2]); - mLights.Add(Light); - - mMouseToolDistance = Target; - - ClearSelectionAndSetFocus(Light, LC_LIGHT_SECTION_TARGET); -} - -void lcModel::UpdateSpotLightTool(const lcVector3& Position) -{ - lcLight* Light = mLights[mLights.GetSize() - 1]; - - Light->Move(1, false, Position - mMouseToolDistance); - Light->UpdatePosition(1); - - mMouseToolDistance = Position; - - gMainWindow->UpdateSelectedObjects(false); - gMainWindow->UpdateAllViews(); -} - -void lcModel::BeginCameraTool(const lcVector3& Position, const lcVector3& Target) -{ - lcCamera* Camera = new lcCamera(Position[0], Position[1], Position[2], Target[0], Target[1], Target[2]); - Camera->CreateName(mCameras); - mCameras.Add(Camera); - - mMouseToolDistance = Position; - - ClearSelectionAndSetFocus(Camera, LC_CAMERA_SECTION_TARGET); -} - -void lcModel::UpdateCameraTool(const lcVector3& Position) -{ - lcCamera* Camera = mCameras[mCameras.GetSize() - 1]; - - Camera->Move(1, false, Position - mMouseToolDistance); - Camera->UpdatePosition(1); - - mMouseToolDistance = Position; - - gMainWindow->UpdateSelectedObjects(false); - gMainWindow->UpdateAllViews(); -} - -void lcModel::UpdateMoveTool(const lcVector3& Distance, bool AlternateButtonDrag) -{ - lcVector3 PieceDistance = LockVector(SnapPosition(Distance) - SnapPosition(mMouseToolDistance)); - lcVector3 ObjectDistance = Distance - mMouseToolDistance; - - MoveSelectedObjects(PieceDistance, ObjectDistance, true, AlternateButtonDrag, true, false); - mMouseToolDistance = Distance; - - gMainWindow->UpdateSelectedObjects(false); - gMainWindow->UpdateAllViews(); -} - -void lcModel::UpdateRotateTool(const lcVector3& Angles, bool AlternateButtonDrag) -{ - lcVector3 Delta = LockVector(SnapRotation(Angles) - SnapRotation(mMouseToolDistance)); - RotateSelectedPieces(Delta, true, AlternateButtonDrag, false, false); - mMouseToolDistance = Angles; - - gMainWindow->UpdateSelectedObjects(false); - gMainWindow->UpdateAllViews(); -} - -void lcModel::UpdateScaleTool(const float Scale) -{ - ScaleSelectedPieces(Scale, true, false); - - gMainWindow->UpdateSelectedObjects(false); - gMainWindow->UpdateAllViews(); -} - -void lcModel::EraserToolClicked(lcObject* Object) -{ - if (!Object) - return; - - switch (Object->GetType()) - { - case LC_OBJECT_PIECE: - mPieces.Remove((lcPiece*)Object); - RemoveEmptyGroups(); - break; - - case LC_OBJECT_CAMERA: - { - const lcArray* Views = gMainWindow->GetViewsForModel(this); - for (int ViewIdx = 0; ViewIdx < Views->GetSize(); ViewIdx++) - { - View* View = (*Views)[ViewIdx]; - lcCamera* Camera = View->mCamera; - - if (Camera == Object) - View->SetCamera(Camera, true); - } - - mCameras.Remove((lcCamera*)Object); - - gMainWindow->UpdateCameraMenu(); - } - break; - - case LC_OBJECT_LIGHT: - mLights.Remove((lcLight*)Object); - break; - } - - delete Object; - gMainWindow->UpdateTimeline(false, false); - gMainWindow->UpdateSelectedObjects(true); - gMainWindow->UpdateAllViews(); - SaveCheckpoint(tr("Deleting")); -} - -void lcModel::PaintToolClicked(lcObject* Object) -{ - if (!Object || Object->GetType() != LC_OBJECT_PIECE) - return; - - lcPiece* Piece = (lcPiece*)Object; - - if (Piece->mColorIndex != gMainWindow->mColorIndex) - { - Piece->SetColorIndex(gMainWindow->mColorIndex); - - SaveCheckpoint(tr("Painting")); - gMainWindow->UpdateSelectedObjects(false); - gMainWindow->UpdateAllViews(); - gMainWindow->UpdateTimeline(false, true); - } -} - -void lcModel::UpdateZoomTool(lcCamera* Camera, float Mouse) -{ - Camera->Zoom(Mouse - mMouseToolDistance.x, mCurrentStep, gMainWindow->GetAddKeys()); - mMouseToolDistance.x = Mouse; - gMainWindow->UpdateAllViews(); -} - -void lcModel::UpdatePanTool(lcCamera* Camera, const lcVector3& Distance) -{ - Camera->Pan(Distance - mMouseToolDistance, mCurrentStep, gMainWindow->GetAddKeys()); - mMouseToolDistance = Distance; - gMainWindow->UpdateAllViews(); -} - -void lcModel::UpdateOrbitTool(lcCamera* Camera, float MouseX, float MouseY) -{ - lcVector3 Center; - GetSelectionCenter(Center); - Camera->Orbit(MouseX - mMouseToolDistance.x, MouseY - mMouseToolDistance.y, Center, mCurrentStep, gMainWindow->GetAddKeys()); - mMouseToolDistance.x = MouseX; - mMouseToolDistance.y = MouseY; - gMainWindow->UpdateAllViews(); -} - -void lcModel::UpdateRollTool(lcCamera* Camera, float Mouse) -{ - Camera->Roll(Mouse - mMouseToolDistance.x, mCurrentStep, gMainWindow->GetAddKeys()); - mMouseToolDistance.x = Mouse; - gMainWindow->UpdateAllViews(); -} - -void lcModel::ZoomRegionToolClicked(lcCamera* Camera, float AspectRatio, const lcVector3& Position, const lcVector3& TargetPosition, const lcVector3* Corners) -{ - Camera->ZoomRegion(AspectRatio, Position, TargetPosition, Corners, mCurrentStep, gMainWindow->GetAddKeys()); - - gMainWindow->UpdateSelectedObjects(false); - gMainWindow->UpdateAllViews(); - - if (!Camera->IsSimple()) - SaveCheckpoint(tr("Zoom")); -} - -void lcModel::LookAt(lcCamera* Camera) -{ - lcVector3 Center; - - if (!GetSelectionCenter(Center)) - { - lcVector3 Min(FLT_MAX, FLT_MAX, FLT_MAX), Max(-FLT_MAX, -FLT_MAX, -FLT_MAX); - - if (GetPiecesBoundingBox(Min, Max)) - Center = (Min + Max) / 2.0f; - else - Center = lcVector3(0.0f, 0.0f, 0.0f); - } - - Camera->Center(Center, mCurrentStep, gMainWindow->GetAddKeys()); - - gMainWindow->UpdateSelectedObjects(false); - gMainWindow->UpdateAllViews(); - - if (!Camera->IsSimple()) - SaveCheckpoint(tr("Look At")); -} - -void lcModel::ZoomExtents(lcCamera* Camera, float Aspect) -{ - lcVector3 Min(FLT_MAX, FLT_MAX, FLT_MAX), Max(-FLT_MAX, -FLT_MAX, -FLT_MAX); - - if (!GetPiecesBoundingBox(Min, Max)) - return; - - lcVector3 Center = (Min + Max) / 2.0f; - - lcVector3 Points[8]; - lcGetBoxCorners(Min, Max, Points); - - Camera->ZoomExtents(Aspect, Center, Points, 8, mCurrentStep, gMainWindow->GetAddKeys()); - - gMainWindow->UpdateSelectedObjects(false); - gMainWindow->UpdateAllViews(); - - if (!Camera->IsSimple()) - SaveCheckpoint(tr("Zoom")); -} - -void lcModel::Zoom(lcCamera* Camera, float Amount) -{ - Camera->Zoom(Amount, mCurrentStep, gMainWindow->GetAddKeys()); - gMainWindow->UpdateSelectedObjects(false); - gMainWindow->UpdateAllViews(); - - if (!Camera->IsSimple()) - SaveCheckpoint(tr("Zoom")); -} - -void lcModel::ShowPropertiesDialog() -{ - lcPropertiesDialogOptions Options; - - Options.Properties = mProperties; - Options.SetDefault = false; - - GetPartsList(gDefaultColor, Options.PartsList); - - if (!gMainWindow->DoDialog(LC_DIALOG_PROPERTIES, &Options)) - return; - - if (Options.SetDefault) - Options.Properties.SaveDefaults(); - - if (mProperties == Options.Properties) - return; - - mProperties = Options.Properties; - - UpdateBackgroundTexture(); - - SaveCheckpoint(tr("Changing Properties")); -} - -void lcModel::ShowSelectByNameDialog() -{ - if (mPieces.IsEmpty() && mCameras.IsEmpty() && mLights.IsEmpty()) - { - QMessageBox::information(gMainWindow, tr("LeoCAD"), tr("Nothing to select.")); - return; - } - - lcQSelectDialog Dialog(gMainWindow); - - if (Dialog.exec() != QDialog::Accepted) - return; - - SetSelectionAndFocus(Dialog.mObjects, NULL, 0); -} - -void lcModel::ShowArrayDialog() -{ - lcVector3 Center; - - if (!GetPieceFocusOrSelectionCenter(Center)) - { - QMessageBox::information(gMainWindow, tr("LeoCAD"), tr("No pieces selected.")); - return; - } - - lcQArrayDialog Dialog(gMainWindow); - - if (Dialog.exec() != QDialog::Accepted) - return; - - if (Dialog.mCounts[0] * Dialog.mCounts[1] * Dialog.mCounts[2] < 2) - { - QMessageBox::information(gMainWindow, tr("LeoCAD"), tr("Array only has 1 element or less, no pieces added.")); - return; - } - - lcArray NewPieces; - - for (int Step1 = 0; Step1 < Dialog.mCounts[0]; Step1++) - { - for (int Step2 = 0; Step2 < Dialog.mCounts[1]; Step2++) - { - for (int Step3 = (Step1 == 0 && Step2 == 0) ? 1 : 0; Step3 < Dialog.mCounts[2]; Step3++) - { - lcMatrix44 ModelWorld; - lcVector3 Position; - - lcVector3 RotationAngles = Dialog.mRotations[0] * Step1 + Dialog.mRotations[1] * Step2 + Dialog.mRotations[2] * Step3; - lcVector3 Offset = Dialog.mOffsets[0] * Step1 + Dialog.mOffsets[1] * Step2 + Dialog.mOffsets[2] * Step3; - - for (int PieceIdx = 0; PieceIdx < mPieces.GetSize(); PieceIdx++) - { - lcPiece* Piece = mPieces[PieceIdx]; - - if (!Piece->IsSelected()) - continue; - - ModelWorld = Piece->mModelWorld; - - ModelWorld.r[3] -= lcVector4(Center, 0.0f); - ModelWorld = lcMul(ModelWorld, lcMatrix44RotationX(RotationAngles[0] * LC_DTOR)); - ModelWorld = lcMul(ModelWorld, lcMatrix44RotationY(RotationAngles[1] * LC_DTOR)); - ModelWorld = lcMul(ModelWorld, lcMatrix44RotationZ(RotationAngles[2] * LC_DTOR)); - ModelWorld.r[3] += lcVector4(Center, 0.0f); - - Position = lcVector3(ModelWorld.r[3].x, ModelWorld.r[3].y, ModelWorld.r[3].z); - ModelWorld.SetTranslation(Position + Offset); - - lcPiece* NewPiece = new lcPiece(Piece->mPieceInfo); - NewPiece->Initialize(ModelWorld, mCurrentStep); - NewPiece->SetColorIndex(Piece->mColorIndex); - - NewPieces.Add(NewPiece); - } - } - } - } - - for (int PieceIdx = 0; PieceIdx < NewPieces.GetSize(); PieceIdx++) - { - lcPiece* Piece = (lcPiece*)NewPieces[PieceIdx]; - Piece->UpdatePosition(mCurrentStep); - AddPiece(Piece); - } - - AddToSelection(NewPieces); - gMainWindow->UpdateTimeline(false, false); - SaveCheckpoint(tr("Array")); -} - -void lcModel::ShowMinifigDialog() -{ - lcQMinifigDialog Dialog(gMainWindow); - - if (Dialog.exec() != QDialog::Accepted) - return; - - gMainWindow->mPreviewWidget->MakeCurrent(); - - lcGroup* Group = AddGroup(tr("Minifig #"), NULL); - lcArray Pieces(LC_MFW_NUMITEMS); - lcMinifig& Minifig = Dialog.mMinifigWidget->mMinifig; - - for (int PartIdx = 0; PartIdx < LC_MFW_NUMITEMS; PartIdx++) - { - if (Minifig.Parts[PartIdx] == NULL) - continue; - - lcPiece* Piece = new lcPiece(Minifig.Parts[PartIdx]); - - Piece->Initialize(Minifig.Matrices[PartIdx], mCurrentStep); - Piece->SetColorIndex(Minifig.Colors[PartIdx]); - Piece->SetGroup(Group); - AddPiece(Piece); - Piece->UpdatePosition(mCurrentStep); - - Pieces.Add(Piece); - } - - SetSelectionAndFocus(Pieces, NULL, 0); - gMainWindow->UpdateTimeline(false, false); - SaveCheckpoint(tr("Minifig")); -} - -void lcModel::UpdateInterface() -{ - gMainWindow->UpdateTimeline(true, false); - gMainWindow->UpdateUndoRedo(mUndoHistory.GetSize() > 1 ? mUndoHistory[0]->Description : NULL, !mRedoHistory.IsEmpty() ? mRedoHistory[0]->Description : NULL); - gMainWindow->UpdatePaste(!g_App->mClipboard.isEmpty()); - gMainWindow->UpdateCategories(); - gMainWindow->UpdateTitle(); - gMainWindow->SetTool(gMainWindow->GetTool()); - - gMainWindow->UpdateSelectedObjects(true); - gMainWindow->SetTransformType(gMainWindow->GetTransformType()); - gMainWindow->UpdateLockSnap(); - gMainWindow->UpdateSnap(); - gMainWindow->UpdateCameraMenu(); - gMainWindow->UpdateModels(); - gMainWindow->UpdatePerspective(); - gMainWindow->UpdateCurrentStep(); -} +#include "lc_global.h" +#include "lc_model.h" +#include +#include "piece.h" +#include "camera.h" +#include "light.h" +#include "group.h" +#include "lc_mainwindow.h" +#include "lc_profile.h" +#include "lc_library.h" +#include "lc_texture.h" +#include "lc_synth.h" +#include "lc_file.h" +#include "pieceinf.h" +#include "view.h" +#include "preview.h" +#include "minifig.h" +#include "lc_qarraydialog.h" +#include "lc_qselectdialog.h" +#include "lc_qminifigdialog.h" +#include "lc_qgroupdialog.h" +#include "lc_qeditgroupsdialog.h" +#include "lc_qutils.h" + +void lcModelProperties::LoadDefaults() +{ + mAuthor = lcGetProfileString(LC_PROFILE_DEFAULT_AUTHOR_NAME); + + mBackgroundType = (lcBackgroundType)lcGetProfileInt(LC_PROFILE_DEFAULT_BACKGROUND_TYPE); + mBackgroundSolidColor = lcVector3FromColor(lcGetProfileInt(LC_PROFILE_DEFAULT_BACKGROUND_COLOR)); + mBackgroundGradientColor1 = lcVector3FromColor(lcGetProfileInt(LC_PROFILE_DEFAULT_GRADIENT_COLOR1)); + mBackgroundGradientColor2 = lcVector3FromColor(lcGetProfileInt(LC_PROFILE_DEFAULT_GRADIENT_COLOR2)); + mBackgroundImage = lcGetProfileString(LC_PROFILE_DEFAULT_BACKGROUND_TEXTURE); + mBackgroundImageTile = lcGetProfileInt(LC_PROFILE_DEFAULT_BACKGROUND_TILE); + + mFogEnabled = lcGetProfileInt(LC_PROFILE_DEFAULT_FOG_ENABLED); + mFogDensity = lcGetProfileFloat(LC_PROFILE_DEFAULT_FOG_DENSITY); + mFogColor = lcVector3FromColor(lcGetProfileInt(LC_PROFILE_DEFAULT_FOG_COLOR)); + mAmbientColor = lcVector3FromColor(lcGetProfileInt(LC_PROFILE_DEFAULT_AMBIENT_COLOR)); +} + +void lcModelProperties::SaveDefaults() +{ + lcSetProfileInt(LC_PROFILE_DEFAULT_BACKGROUND_TYPE, mBackgroundType); + lcSetProfileInt(LC_PROFILE_DEFAULT_BACKGROUND_COLOR, lcColorFromVector3(mBackgroundSolidColor)); + lcSetProfileInt(LC_PROFILE_DEFAULT_GRADIENT_COLOR1, lcColorFromVector3(mBackgroundGradientColor1)); + lcSetProfileInt(LC_PROFILE_DEFAULT_GRADIENT_COLOR2, lcColorFromVector3(mBackgroundGradientColor2)); + lcSetProfileString(LC_PROFILE_DEFAULT_BACKGROUND_TEXTURE, mBackgroundImage); + lcSetProfileInt(LC_PROFILE_DEFAULT_BACKGROUND_TILE, mBackgroundImageTile); + + lcSetProfileInt(LC_PROFILE_DEFAULT_FOG_ENABLED, mFogEnabled); + lcSetProfileFloat(LC_PROFILE_DEFAULT_FOG_DENSITY, mFogDensity); + lcSetProfileInt(LC_PROFILE_DEFAULT_FOG_COLOR, lcColorFromVector3(mFogColor)); + lcSetProfileInt(LC_PROFILE_DEFAULT_AMBIENT_COLOR, lcColorFromVector3(mAmbientColor)); +} + +void lcModelProperties::SaveLDraw(QTextStream& Stream) const +{ + QLatin1String LineEnding("\r\n"); + + if (!mAuthor.isEmpty()) + Stream << QLatin1String("0 !LEOCAD MODEL AUTHOR ") << mAuthor << LineEnding; + + if (!mDescription.isEmpty()) + Stream << QLatin1String("0 !LEOCAD MODEL DESCRIPTION ") << mDescription << LineEnding; + + if (!mComments.isEmpty()) + { + QStringList Comments = mComments.split('\n'); + foreach (const QString& Comment, Comments) + Stream << QLatin1String("0 !LEOCAD MODEL COMMENT ") << Comment << LineEnding; + } + + bool TypeChanged = (mBackgroundType != lcGetDefaultProfileInt(LC_PROFILE_DEFAULT_BACKGROUND_TYPE)); + + switch (mBackgroundType) + { + case LC_BACKGROUND_SOLID: + if (mBackgroundSolidColor != lcVector3FromColor(lcGetDefaultProfileInt(LC_PROFILE_DEFAULT_BACKGROUND_COLOR)) || TypeChanged) + Stream << QLatin1String("0 !LEOCAD MODEL BACKGROUND COLOR ") << mBackgroundSolidColor[0] << ' ' << mBackgroundSolidColor[1] << ' ' << mBackgroundSolidColor[2] << LineEnding; + break; + + case LC_BACKGROUND_GRADIENT: + if (mBackgroundGradientColor1 != lcVector3FromColor(lcGetProfileInt(LC_PROFILE_DEFAULT_GRADIENT_COLOR1)) || + mBackgroundGradientColor2 != lcVector3FromColor(lcGetProfileInt(LC_PROFILE_DEFAULT_GRADIENT_COLOR2)) || TypeChanged) + Stream << QLatin1String("0 !LEOCAD MODEL BACKGROUND GRADIENT ") << mBackgroundGradientColor1[0] << ' ' << mBackgroundGradientColor1[1] << ' ' << mBackgroundGradientColor1[2] << ' ' << mBackgroundGradientColor2[0] << ' ' << mBackgroundGradientColor2[1] << ' ' << mBackgroundGradientColor2[2] << LineEnding; + break; + + case LC_BACKGROUND_IMAGE: + if (!mBackgroundImage.isEmpty()) + { + Stream << QLatin1String("0 !LEOCAD MODEL BACKGROUND IMAGE "); + if (mBackgroundImageTile) + Stream << QLatin1String("TILE "); + Stream << QLatin1String("NAME ") << mBackgroundImage << LineEnding; + } + break; + } + +// bool mFogEnabled; +// float mFogDensity; +// lcVector3 mFogColor; +// lcVector3 mAmbientColor; +} + +void lcModelProperties::ParseLDrawLine(QTextStream& Stream) +{ + QString Token; + Stream >> Token; + + if (Token == QLatin1String("AUTHOR")) + mAuthor = Stream.readLine().mid(1); + else if (Token == QLatin1String("DESCRIPTION")) + mDescription = Stream.readLine().mid(1); + else if (Token == QLatin1String("COMMENT")) + { + QString Comment = Stream.readLine().mid(1); + if (!mComments.isEmpty()) + mComments += '\n'; + mComments += Comment; + } + else if (Token == QLatin1String("BACKGROUND")) + { + Stream >> Token; + + if (Token == QLatin1String("COLOR")) + { + mBackgroundType = LC_BACKGROUND_SOLID; + Stream >> mBackgroundSolidColor[0] >> mBackgroundSolidColor[1] >> mBackgroundSolidColor[2]; + } + else if (Token == QLatin1String("GRADIENT")) + { + mBackgroundType = LC_BACKGROUND_GRADIENT; + Stream >> mBackgroundGradientColor1[0] >> mBackgroundGradientColor1[1] >> mBackgroundGradientColor1[2] >> mBackgroundGradientColor2[0] >> mBackgroundGradientColor2[1] >> mBackgroundGradientColor2[2]; + } + else if (Token == QLatin1String("IMAGE")) + { + Stream >> Token; + + if (Token == QLatin1String("TILE")) + { + mBackgroundImageTile = true; + Stream >> Token; + } + + if (Token == QLatin1String("NAME")) + mBackgroundImage = Stream.readLine().trimmed(); + } + } +} + +lcModel::lcModel(const QString& Name) +{ + mProperties.mName = Name; + mProperties.LoadDefaults(); + + mActive = false; + mCurrentStep = 1; + mBackgroundTexture = NULL; + mPieceInfo = NULL; +} + +lcModel::~lcModel() +{ + if (mPieceInfo) + { + if (gMainWindow && gMainWindow->mPreviewWidget->GetCurrentPiece() == mPieceInfo) + gMainWindow->mPreviewWidget->SetDefaultPiece(); + + if (mPieceInfo->GetModel() == this) + mPieceInfo->SetPlaceholder(); + mPieceInfo->Release(true); + } + + DeleteModel(); + DeleteHistory(); +} + +bool lcModel::IncludesModel(const lcModel* Model) const +{ + if (Model == this) + return true; + + for (int PieceIdx = 0; PieceIdx < mPieces.GetSize(); PieceIdx++) + if (mPieces[PieceIdx]->mPieceInfo->IncludesModel(Model)) + return true; + + return false; +} + +void lcModel::DeleteHistory() +{ + mUndoHistory.DeleteAll(); + mRedoHistory.DeleteAll(); +} + +void lcModel::DeleteModel() +{ + lcReleaseTexture(mBackgroundTexture); + mBackgroundTexture = NULL; + + if (gMainWindow) + { + const lcArray* Views = gMainWindow->GetViewsForModel(this); + + // TODO: this is only needed to avoid a dangling pointer during undo/redo if a camera is set to a view but we should find a better solution instead + if (Views) + { + for (int ViewIdx = 0; ViewIdx < Views->GetSize(); ViewIdx++) + { + View* View = (*Views)[ViewIdx]; + lcCamera* Camera = View->mCamera; + + if (!Camera->IsSimple() && mCameras.FindIndex(Camera) != -1) + View->SetCamera(Camera, true); + } + } + } + + mPieces.DeleteAll(); + mCameras.DeleteAll(); + mLights.DeleteAll(); + mGroups.DeleteAll(); + mFileLines.clear(); +} + +void lcModel::CreatePieceInfo(Project* Project) +{ + mPieceInfo = lcGetPiecesLibrary()->FindPiece(mProperties.mName.toUpper().toLatin1().constData(), Project, true); + mPieceInfo->SetModel(this, true); + mPieceInfo->AddRef(); +} + +void lcModel::UpdatePieceInfo(lcArray& UpdatedModels) +{ + if (UpdatedModels.FindIndex(this) != -1) + return; + + mPieceInfo->SetModel(this, false); + UpdatedModels.Add(this); + + lcMesh* Mesh = mPieceInfo->GetMesh(); + + if (mPieces.IsEmpty() && !Mesh) + { + mPieceInfo->SetBoundingBox(lcVector3(0.0f, 0.0f, 0.0f), lcVector3(0.0f, 0.0f, 0.0f)); + return; + } + + lcVector3 Min(FLT_MAX, FLT_MAX, FLT_MAX), Max(-FLT_MAX, -FLT_MAX, -FLT_MAX); + + for (int PieceIdx = 0; PieceIdx < mPieces.GetSize(); PieceIdx++) + { + lcPiece* Piece = mPieces[PieceIdx]; + + if (Piece->GetStepHide() == LC_STEP_MAX) + { + Piece->mPieceInfo->UpdateBoundingBox(UpdatedModels); + Piece->CompareBoundingBox(Min, Max); + } + } + + if (Mesh) + { + Min = lcMin(Min, Mesh->mBoundingBox.Min); + Max = lcMax(Max, Mesh->mBoundingBox.Max); + } + + mPieceInfo->SetBoundingBox(Min, Max); +} + +void lcModel::SaveLDraw(QTextStream& Stream, bool SelectedOnly) const +{ + QLatin1String LineEnding("\r\n"); + + mProperties.SaveLDraw(Stream); + + if (mCurrentStep != GetLastStep()) + Stream << QLatin1String("0 !LEOCAD MODEL CURRENT_STEP") << mCurrentStep << LineEnding; + + lcArray CurrentGroups; + lcStep Step = 1; + int CurrentLine = 0; + + for (int PieceIdx = 0; PieceIdx < mPieces.GetSize(); PieceIdx++) + { + lcPiece* Piece = mPieces[PieceIdx]; + + if (SelectedOnly && !Piece->IsSelected()) + continue; + + while (Piece->GetFileLine() > CurrentLine && CurrentLine < mFileLines.size()) + { + QString Line = mFileLines[CurrentLine]; + QTextStream LineStream(&Line, QIODevice::ReadOnly); + + QString Token; + LineStream >> Token; + bool Skip = false; + + if (Token == QLatin1String("0")) + { + LineStream >> Token; + + if (Token == QLatin1String("STEP")) + { + if (Piece->GetStepShow() > Step) + Step++; + else + Skip = true; + } + } + + if (!Skip) + Stream << mFileLines[CurrentLine]; + CurrentLine++; + } + + while (Piece->GetStepShow() > Step) + { + Stream << QLatin1String("0 STEP\r\n"); + Step++; + } + + lcGroup* PieceGroup = Piece->GetGroup(); + + if (PieceGroup) + { + if (CurrentGroups.IsEmpty() || (!CurrentGroups.IsEmpty() && PieceGroup != CurrentGroups[CurrentGroups.GetSize() - 1])) + { + lcArray PieceParents; + + for (lcGroup* Group = PieceGroup; Group; Group = Group->mGroup) + PieceParents.InsertAt(0, Group); + + int FoundParent = -1; + + while (!CurrentGroups.IsEmpty()) + { + lcGroup* Group = CurrentGroups[CurrentGroups.GetSize() - 1]; + int Index = PieceParents.FindIndex(Group); + + if (Index == -1) + { + CurrentGroups.RemoveIndex(CurrentGroups.GetSize() - 1); + Stream << QLatin1String("0 !LEOCAD GROUP END\r\n"); + } + else + { + FoundParent = Index; + break; + } + } + + for (int ParentIdx = FoundParent + 1; ParentIdx < PieceParents.GetSize(); ParentIdx++) + { + lcGroup* Group = PieceParents[ParentIdx]; + CurrentGroups.Add(Group); + Stream << QLatin1String("0 !LEOCAD GROUP BEGIN ") << Group->mName << LineEnding; + } + } + } + else + { + while (CurrentGroups.GetSize()) + { + CurrentGroups.RemoveIndex(CurrentGroups.GetSize() - 1); + Stream << QLatin1String("0 !LEOCAD GROUP END\r\n"); + } + } + + if (Piece->mPieceInfo->GetSynthInfo()) + { + Stream << QLatin1String("0 !LEOCAD SYNTH BEGIN\r\n"); + + const lcArray& ControlPoints = Piece->GetControlPoints(); + for (int ControlPointIdx = 0; ControlPointIdx < ControlPoints.GetSize(); ControlPointIdx++) + { + const lcPieceControlPoint& ControlPoint = ControlPoints[ControlPointIdx]; + + Stream << QLatin1String("0 !LEOCAD SYNTH CONTROL_POINT"); + + const float* FloatMatrix = ControlPoint.Transform; + float Numbers[13] = { FloatMatrix[12], -FloatMatrix[14], FloatMatrix[13], FloatMatrix[0], -FloatMatrix[8], FloatMatrix[4], -FloatMatrix[2], FloatMatrix[10], -FloatMatrix[6], FloatMatrix[1], -FloatMatrix[9], FloatMatrix[5], ControlPoint.Scale }; + + for (int NumberIdx = 0; NumberIdx < 13; NumberIdx++) + Stream << ' ' << lcFormatValue(Numbers[NumberIdx]); + + Stream << LineEnding; + } + } + + Piece->SaveLDraw(Stream); + + if (Piece->mPieceInfo->GetSynthInfo()) + Stream << QLatin1String("0 !LEOCAD SYNTH END\r\n"); + } + + while (CurrentLine < mFileLines.size()) + { + Stream << mFileLines[CurrentLine]; + CurrentLine++; + } + + while (CurrentGroups.GetSize()) + { + CurrentGroups.RemoveIndex(CurrentGroups.GetSize() - 1); + Stream << QLatin1String("0 !LEOCAD GROUP END\r\n"); + } + + for (int CameraIdx = 0; CameraIdx < mCameras.GetSize(); CameraIdx++) + { + lcCamera* Camera = mCameras[CameraIdx]; + + if (!SelectedOnly || Camera->IsSelected()) + Camera->SaveLDraw(Stream); + } + + for (int LightIdx = 0; LightIdx < mLights.GetSize(); LightIdx++) + { + lcLight* Light = mLights[LightIdx]; + + if (!SelectedOnly || Light->IsSelected()) + Light->SaveLDraw(Stream); + } + + Stream.flush(); +} + +void lcModel::LoadLDraw(QIODevice& Device, Project* Project) +{ + lcPiece* Piece = NULL; + lcCamera* Camera = NULL; + lcLight* Light = NULL; + lcArray CurrentGroups; + lcArray ControlPoints; + int CurrentStep = 1; + + mProperties.mAuthor.clear(); + + while (!Device.atEnd()) + { + qint64 Pos = Device.pos(); + QString OriginalLine = Device.readLine(); + QString Line = OriginalLine.trimmed(); + QTextStream LineStream(&Line, QIODevice::ReadOnly); + + QString Token; + LineStream >> Token; + + if (Token == QLatin1String("0")) + { + LineStream >> Token; + + if (Token == QLatin1String("FILE")) + { + if (!mProperties.mName.isEmpty()) + { + Device.seek(Pos); + break; + } + + mProperties.mName = LineStream.readAll().trimmed(); + continue; + } + else if (Token == QLatin1String("NOFILE")) + { + break; + } + else if (Token == QLatin1String("STEP")) + { + CurrentStep++; + mFileLines.append(OriginalLine); + continue; + } + + if (Token != QLatin1String("!LEOCAD")) + { + mFileLines.append(OriginalLine); + continue; + } + + LineStream >> Token; + + if (Token == QLatin1String("MODEL")) + { + mProperties.ParseLDrawLine(LineStream); + } + else if (Token == QLatin1String("PIECE")) + { + if (!Piece) + Piece = new lcPiece(NULL); + + Piece->ParseLDrawLine(LineStream); + } + else if (Token == QLatin1String("CAMERA")) + { + if (!Camera) + Camera = new lcCamera(false); + + if (Camera->ParseLDrawLine(LineStream)) + { + Camera->CreateName(mCameras); + mCameras.Add(Camera); + Camera = NULL; + } + } + else if (Token == QLatin1String("LIGHT")) + { + } + else if (Token == QLatin1String("GROUP")) + { + LineStream >> Token; + + if (Token == QLatin1String("BEGIN")) + { + QString Name = LineStream.readAll().trimmed(); + QByteArray NameUtf = Name.toUtf8(); // todo: replace with qstring + lcGroup* Group = GetGroup(NameUtf.constData(), true); + if (!CurrentGroups.IsEmpty()) + Group->mGroup = CurrentGroups[CurrentGroups.GetSize() - 1]; + else + Group->mGroup = NULL; + CurrentGroups.Add(Group); + } + else if (Token == QLatin1String("END")) + { + if (!CurrentGroups.IsEmpty()) + CurrentGroups.RemoveIndex(CurrentGroups.GetSize() - 1); + } + } + else if (Token == QLatin1String("SYNTH")) + { + LineStream >> Token; + + if (Token == QLatin1String("BEGIN")) + { + ControlPoints.RemoveAll(); + } + else if (Token == QLatin1String("END")) + { + ControlPoints.RemoveAll(); + } + else if (Token == QLatin1String("CONTROL_POINT")) + { + float Numbers[13]; + for (int TokenIdx = 0; TokenIdx < 13; TokenIdx++) + LineStream >> Numbers[TokenIdx]; + + lcPieceControlPoint& PieceControlPoint = ControlPoints.Add(); + PieceControlPoint.Transform = lcMatrix44(lcVector4(Numbers[3], Numbers[9], -Numbers[6], 0.0f), lcVector4(Numbers[5], Numbers[11], -Numbers[8], 0.0f), + lcVector4(-Numbers[4], -Numbers[10], Numbers[7], 0.0f), lcVector4(Numbers[0], Numbers[2], -Numbers[1], 1.0f)); + PieceControlPoint.Scale = Numbers[12]; + } + } + + continue; + } + else if (Token == QLatin1String("1")) + { + int ColorCode; + LineStream >> ColorCode; + + float IncludeMatrix[12]; + for (int TokenIdx = 0; TokenIdx < 12; TokenIdx++) + LineStream >> IncludeMatrix[TokenIdx]; + + lcMatrix44 IncludeTransform(lcVector4(IncludeMatrix[3], IncludeMatrix[6], IncludeMatrix[9], 0.0f), lcVector4(IncludeMatrix[4], IncludeMatrix[7], IncludeMatrix[10], 0.0f), + lcVector4(IncludeMatrix[5], IncludeMatrix[8], IncludeMatrix[11], 0.0f), lcVector4(IncludeMatrix[0], IncludeMatrix[1], IncludeMatrix[2], 1.0f)); + + QString File = LineStream.readAll().trimmed().toUpper(); + QString PartID = File; + PartID.replace('\\', '/'); + + if (PartID.endsWith(QLatin1String(".DAT"))) + PartID = PartID.left(PartID.size() - 4); + + lcPiecesLibrary* Library = lcGetPiecesLibrary(); + + if (Library->IsPrimitive(PartID.toLatin1().constData())) + { + mFileLines.append(OriginalLine); + } + else + { + if (!Piece) + Piece = new lcPiece(NULL); + + if (!CurrentGroups.IsEmpty()) + Piece->SetGroup(CurrentGroups[CurrentGroups.GetSize() - 1]); + + PieceInfo* Info = Library->FindPiece(PartID.toLatin1().constData(), Project, false); + + if (!Info) + Info = Library->FindPiece(File.toLatin1().constData(), Project, true); + + float* Matrix = IncludeTransform; + lcMatrix44 Transform(lcVector4(Matrix[0], Matrix[2], -Matrix[1], 0.0f), lcVector4(Matrix[8], Matrix[10], -Matrix[9], 0.0f), + lcVector4(-Matrix[4], -Matrix[6], Matrix[5], 0.0f), lcVector4(Matrix[12], Matrix[14], -Matrix[13], 1.0f)); + + Piece->SetFileLine(mFileLines.size()); + Piece->SetPieceInfo(Info); + Piece->Initialize(Transform, CurrentStep); + Piece->SetColorCode(ColorCode); + Piece->SetControlPoints(ControlPoints); + AddPiece(Piece); + Piece = NULL; + } + } + else + mFileLines.append(OriginalLine); + } + + mCurrentStep = CurrentStep; + CalculateStep(mCurrentStep); + UpdateBackgroundTexture(); + lcGetPiecesLibrary()->UnloadUnusedParts(); + + delete Piece; + delete Camera; + delete Light; +} + +bool lcModel::LoadBinary(lcFile* file) +{ + lcint32 i, count; + char id[32]; + lcuint32 rgb; + float fv = 0.4f; + lcuint8 ch; + lcuint16 sh; + + file->Seek(0, SEEK_SET); + file->ReadBuffer(id, 32); + sscanf(&id[7], "%f", &fv); + + if (fv == 0.0f) + { + lconv *loc = localeconv(); + id[8] = loc->decimal_point[0]; + sscanf(&id[7], "%f", &fv); + + if (fv == 0.0f) + return false; + } + + if (fv > 0.4f) + file->ReadFloats(&fv, 1); + + file->ReadU32(&rgb, 1); + mProperties.mBackgroundSolidColor[0] = (float)((unsigned char) (rgb))/255; + mProperties.mBackgroundSolidColor[1] = (float)((unsigned char) (((unsigned short) (rgb)) >> 8))/255; + mProperties.mBackgroundSolidColor[2] = (float)((unsigned char) ((rgb) >> 16))/255; + + if (fv < 0.6f) // old view + { + double eye[3], target[3]; + file->ReadDoubles(eye, 3); + file->ReadDoubles(target, 3); + } + + file->Seek(28, SEEK_CUR); + file->ReadS32(&i, 1); + mCurrentStep = i; + + if (fv > 0.8f) + file->ReadU32();//m_nScene + + file->ReadS32(&count, 1); + lcPiecesLibrary* Library = lcGetPiecesLibrary(); + + int FirstNewPiece = mPieces.GetSize(); + + while (count--) + { + if (fv > 0.4f) + { + lcPiece* pPiece = new lcPiece(NULL); + pPiece->FileLoad(*file); + AddPiece(pPiece); + } + else + { + char name[LC_PIECE_NAME_LEN]; + lcVector3 pos, rot; + lcuint8 color, step, group; + + file->ReadFloats(pos, 3); + file->ReadFloats(rot, 3); + file->ReadU8(&color, 1); + file->ReadBuffer(name, 9); + file->ReadU8(&step, 1); + file->ReadU8(&group, 1); + + pos *= 25.0f; + lcMatrix44 WorldMatrix = lcMul(lcMatrix44RotationZ(rot[2] * LC_DTOR), lcMul(lcMatrix44RotationY(rot[1] * LC_DTOR), lcMatrix44RotationX(rot[0] * LC_DTOR))); + WorldMatrix.SetTranslation(pos); + + PieceInfo* pInfo = Library->FindPiece(name, NULL, true); + lcPiece* pPiece = new lcPiece(pInfo); + + pPiece->Initialize(WorldMatrix, step); + pPiece->SetColorCode(lcGetColorCodeFromOriginalColor(color)); + AddPiece(pPiece); + +// pPiece->SetGroup((lcGroup*)group); + } + } + + if (fv >= 0.4f) + { + file->ReadBuffer(&ch, 1); + if (ch == 0xFF) file->ReadU16(&sh, 1); else sh = ch; + if (sh > 100) + file->Seek(sh, SEEK_CUR); + else + { + String Author; + file->ReadBuffer(Author.GetBuffer(sh), sh); + Author.Buffer()[sh] = 0; + mProperties.mAuthor = QString::fromUtf8(Author.Buffer()); + } + + file->ReadBuffer(&ch, 1); + if (ch == 0xFF) file->ReadU16(&sh, 1); else sh = ch; + if (sh > 100) + file->Seek(sh, SEEK_CUR); + else + { + String Description; + file->ReadBuffer(Description.GetBuffer(sh), sh); + Description.Buffer()[sh] = 0; + mProperties.mDescription = QString::fromUtf8(Description.Buffer()); + } + + file->ReadBuffer(&ch, 1); + if (ch == 0xFF && fv < 1.3f) file->ReadU16(&sh, 1); else sh = ch; + if (sh > 255) + file->Seek(sh, SEEK_CUR); + else + { + String Comments; + file->ReadBuffer(Comments.GetBuffer(sh), sh); + Comments.Buffer()[sh] = 0; + mProperties.mComments = QString::fromUtf8(Comments.Buffer()); + mProperties.mComments.replace(QLatin1String("\r\n"), QLatin1String("\n")); + } + } + + if (fv >= 0.5f) + { + int NumGroups = mGroups.GetSize(); + + file->ReadS32(&count, 1); + for (i = 0; i < count; i++) + mGroups.Add(new lcGroup()); + + for (int GroupIdx = NumGroups; GroupIdx < mGroups.GetSize(); GroupIdx++) + { + lcGroup* Group = mGroups[GroupIdx]; + + if (fv < 1.0f) + { + char Name[LC_MAX_GROUP_NAME + 1]; + file->ReadBuffer(Name, sizeof(Name)); + Group->mName = QString::fromUtf8(Name); + file->ReadBuffer(&ch, 1); + Group->mGroup = (lcGroup*)-1; + } + else + Group->FileLoad(file); + } + + for (int GroupIdx = NumGroups; GroupIdx < mGroups.GetSize(); GroupIdx++) + { + lcGroup* Group = mGroups[GroupIdx]; + + i = LC_POINTER_TO_INT(Group->mGroup); + Group->mGroup = NULL; + + if (i > 0xFFFF || i == -1) + continue; + + Group->mGroup = mGroups[NumGroups + i]; + } + + for (int PieceIdx = FirstNewPiece; PieceIdx < mPieces.GetSize(); PieceIdx++) + { + lcPiece* Piece = mPieces[PieceIdx]; + + i = LC_POINTER_TO_INT(Piece->GetGroup()); + Piece->SetGroup(NULL); + + if (i > 0xFFFF || i == -1) + continue; + + Piece->SetGroup(mGroups[NumGroups + i]); + } + + RemoveEmptyGroups(); + } + + if (fv >= 0.6f) + { + if (fv < 1.0f) + file->Seek(4, SEEK_CUR); + else + file->Seek(2, SEEK_CUR); + + file->ReadS32(&count, 1); + for (i = 0; i < count; i++) + mCameras.Add(new lcCamera(false)); + + if (count < 7) + { + lcCamera* pCam = new lcCamera(false); + for (i = 0; i < count; i++) + pCam->FileLoad(*file); + delete pCam; + } + else + { + for (int CameraIdx = 0; CameraIdx < mCameras.GetSize(); CameraIdx++) + mCameras[CameraIdx]->FileLoad(*file); + } + } + + if (fv >= 0.7f) + { + file->Seek(16, SEEK_CUR); + + file->ReadU32(&rgb, 1); + mProperties.mFogColor[0] = (float)((unsigned char) (rgb))/255; + mProperties.mFogColor[1] = (float)((unsigned char) (((unsigned short) (rgb)) >> 8))/255; + mProperties.mFogColor[2] = (float)((unsigned char) ((rgb) >> 16))/255; + + if (fv < 1.0f) + { + file->ReadU32(&rgb, 1); + mProperties.mFogDensity = (float)rgb/100; + } + else + file->ReadFloats(&mProperties.mFogDensity, 1); + + if (fv < 1.3f) + { + file->ReadU8(&ch, 1); + if (ch == 0xFF) + file->ReadU16(&sh, 1); + sh = ch; + } + else + file->ReadU16(&sh, 1); + + if (sh < LC_MAXPATH) + { + char Background[LC_MAXPATH]; + file->ReadBuffer(Background, sh); + mProperties.mBackgroundImage = Background; + } + else + file->Seek(sh, SEEK_CUR); + } + + if (fv >= 0.8f) + { + file->ReadBuffer(&ch, 1); + file->Seek(ch, SEEK_CUR); + file->ReadBuffer(&ch, 1); + file->Seek(ch, SEEK_CUR); + } + + if (fv > 0.9f) + { + file->ReadU32(&rgb, 1); + mProperties.mAmbientColor[0] = (float)((unsigned char) (rgb))/255; + mProperties.mAmbientColor[1] = (float)((unsigned char) (((unsigned short) (rgb)) >> 8))/255; + mProperties.mAmbientColor[2] = (float)((unsigned char) ((rgb) >> 16))/255; + + if (fv < 1.3f) + file->Seek(23, SEEK_CUR); + else + file->Seek(11, SEEK_CUR); + } + + if (fv > 1.0f) + { + file->ReadU32(&rgb, 1); + mProperties.mBackgroundGradientColor1[0] = (float)((unsigned char) (rgb))/255; + mProperties.mBackgroundGradientColor1[1] = (float)((unsigned char) (((unsigned short) (rgb)) >> 8))/255; + mProperties.mBackgroundGradientColor1[2] = (float)((unsigned char) ((rgb) >> 16))/255; + file->ReadU32(&rgb, 1); + mProperties.mBackgroundGradientColor2[0] = (float)((unsigned char) (rgb))/255; + mProperties.mBackgroundGradientColor2[1] = (float)((unsigned char) (((unsigned short) (rgb)) >> 8))/255; + mProperties.mBackgroundGradientColor2[2] = (float)((unsigned char) ((rgb) >> 16))/255; + } + + UpdateBackgroundTexture(); + CalculateStep(mCurrentStep); + lcGetPiecesLibrary()->UnloadUnusedParts(); + + return true; +} + +void lcModel::Merge(lcModel* Other) +{ + for (int PieceIdx = 0; PieceIdx < Other->mPieces.GetSize(); PieceIdx++) + { + lcPiece* Piece = Other->mPieces[PieceIdx]; + Piece->SetFileLine(-1); + AddPiece(Piece); + } + + Other->mPieces.RemoveAll(); + + for (int CameraIdx = 0; CameraIdx < Other->mCameras.GetSize(); CameraIdx++) + { + lcCamera* Camera = Other->mCameras[CameraIdx]; + Camera->CreateName(mCameras); + mCameras.Add(Camera); + } + + Other->mCameras.RemoveAll(); + + for (int LightIdx = 0; LightIdx < Other->mLights.GetSize(); LightIdx++) + { + lcLight* Light = Other->mLights[LightIdx]; + Light->CreateName(mLights); + mLights.Add(Light); + } + + Other->mLights.RemoveAll(); + + for (int GroupIdx = 0; GroupIdx < Other->mGroups.GetSize(); GroupIdx++) + { + lcGroup* Group = Other->mGroups[GroupIdx]; + Group->CreateName(mGroups); + mGroups.Add(Group); + } + + Other->mGroups.RemoveAll(); + + delete Other; + + gMainWindow->UpdateTimeline(false, false); +} + +void lcModel::Cut() +{ + Copy(); + + if (RemoveSelectedObjects()) + { + gMainWindow->UpdateTimeline(false, false); + gMainWindow->UpdateSelectedObjects(true); + gMainWindow->UpdateAllViews(); + SaveCheckpoint("Cutting"); + } +} + +void lcModel::Copy() +{ + QByteArray File; + QTextStream Stream(&File, QIODevice::WriteOnly); + + SaveLDraw(Stream, true); + + g_App->ExportClipboard(File); +} + +void lcModel::Paste() +{ + if (g_App->mClipboard.isEmpty()) + return; + + lcModel* Model = new lcModel(QString()); + + QBuffer Buffer(&g_App->mClipboard); + Buffer.open(QIODevice::ReadOnly); + Model->LoadLDraw(Buffer, lcGetActiveProject()); + + const lcArray& PastedPieces = Model->mPieces; + lcArray SelectedObjects; + SelectedObjects.AllocGrow(PastedPieces.GetSize()); + + for (int PieceIdx = 0; PieceIdx < PastedPieces.GetSize(); PieceIdx++) + { + lcPiece* Piece = PastedPieces[PieceIdx]; + lcStep Step = Piece->GetStepShow(); + + if (Step > mCurrentStep) + Piece->SetStepShow(mCurrentStep); + + SelectedObjects.Add(Piece); + } + + Merge(Model); + SaveCheckpoint(tr("Pasting")); + + if (PastedPieces.GetSize() == 1) + ClearSelectionAndSetFocus(PastedPieces[0], LC_PIECE_SECTION_POSITION); + else + SetSelectionAndFocus(SelectedObjects, NULL, 0); + + CalculateStep(mCurrentStep); + gMainWindow->UpdateTimeline(false, false); + gMainWindow->UpdateAllViews(); +} + +void lcModel::GetScene(lcScene& Scene, lcCamera* ViewCamera, bool DrawInterface) const +{ + Scene.Begin(ViewCamera->mWorldView); + + mPieceInfo->AddRenderMesh(Scene); + + for (int PieceIdx = 0; PieceIdx < mPieces.GetSize(); PieceIdx++) + { + lcPiece* Piece = mPieces[PieceIdx]; + + if (Piece->IsVisible(mCurrentStep)) + Piece->AddRenderMeshes(Scene, DrawInterface); + } + + if (DrawInterface) + { + for (int CameraIdx = 0; CameraIdx < mCameras.GetSize(); CameraIdx++) + { + lcCamera* Camera = mCameras[CameraIdx]; + + if (Camera != ViewCamera && Camera->IsVisible()) + Scene.mInterfaceObjects.Add(Camera); + } + + for (int LightIdx = 0; LightIdx < mLights.GetSize(); LightIdx++) + { + lcLight* Light = mLights[LightIdx]; + + if (Light->IsVisible()) + Scene.mInterfaceObjects.Add(Light); + } + } + + Scene.End(); +} + +void lcModel::SubModelAddRenderMeshes(lcScene& Scene, const lcMatrix44& WorldMatrix, int DefaultColorIndex, bool Focused, bool Selected) const +{ + for (int PieceIdx = 0; PieceIdx < mPieces.GetSize(); PieceIdx++) + { + lcPiece* Piece = mPieces[PieceIdx]; + + if (Piece->GetStepHide() != LC_STEP_MAX) + continue; + + int ColorIndex = Piece->mColorIndex; + + if (ColorIndex == gDefaultColor) + ColorIndex = DefaultColorIndex; + + PieceInfo* Info = Piece->mPieceInfo; + Info->AddRenderMeshes(Scene, lcMul(Piece->mModelWorld, WorldMatrix), ColorIndex, Focused, Selected); + } +} + +void lcModel::DrawBackground(lcContext* Context) +{ + if (mProperties.mBackgroundType == LC_BACKGROUND_SOLID) + { + glClearColor(mProperties.mBackgroundSolidColor[0], mProperties.mBackgroundSolidColor[1], mProperties.mBackgroundSolidColor[2], 0.0f); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + return; + } + + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + glDepthMask(GL_FALSE); + glDisable(GL_DEPTH_TEST); + glDisable(GL_LIGHTING); + + float ViewWidth = (float)Context->GetViewportWidth(); + float ViewHeight = (float)Context->GetViewportHeight(); + + Context->SetWorldMatrix(lcMatrix44Identity()); + Context->SetViewMatrix(lcMatrix44Translation(lcVector3(0.375, 0.375, 0.0))); + Context->SetProjectionMatrix(lcMatrix44Ortho(0.0f, ViewWidth, 0.0f, ViewHeight, -1.0f, 1.0f)); + + if (mProperties.mBackgroundType == LC_BACKGROUND_GRADIENT) + { + glShadeModel(GL_SMOOTH); + + const lcVector3& Color1 = mProperties.mBackgroundGradientColor1; + const lcVector3& Color2 = mProperties.mBackgroundGradientColor2; + + float Verts[] = + { + ViewWidth, ViewHeight, Color1[0], Color1[1], Color1[2], 1.0f, + 0.0f, ViewHeight, Color1[0], Color1[1], Color1[2], 1.0f, + 0.0f, 0.0f, Color2[0], Color2[1], Color2[2], 1.0f, + ViewWidth, 0.0f, Color2[0], Color2[1], Color2[2], 1.0f + }; + + Context->SetProgram(LC_PROGRAM_VERTEX_COLOR); + Context->SetVertexBufferPointer(Verts); + Context->SetVertexFormat(0, 2, 0, 4); + + Context->DrawPrimitives(GL_TRIANGLE_FAN, 0, 4); + + Context->ClearVertexBuffer(); // context remove + + glShadeModel(GL_FLAT); + } + else if (mProperties.mBackgroundType == LC_BACKGROUND_IMAGE) + { + glEnable(GL_TEXTURE_2D); + + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); + glBindTexture(GL_TEXTURE_2D, mBackgroundTexture->mTexture); + + float TileWidth = 1.0f, TileHeight = 1.0f; + + if (mProperties.mBackgroundImageTile) + { + TileWidth = ViewWidth / mBackgroundTexture->mWidth; + TileHeight = ViewHeight / mBackgroundTexture->mHeight; + } + + float Verts[] = + { + 0.0f, ViewHeight, 0.0f, 0.0f, + ViewWidth, ViewHeight, TileWidth, 0.0f, + ViewWidth, 0.0f, TileWidth, TileHeight, + 0.0f, 0.0f, 0.0f, TileHeight + }; + + Context->SetProgram(LC_PROGRAM_TEXTURE); + Context->SetVertexBufferPointer(Verts); + Context->SetVertexFormat(0, 2, 2, 0); + + Context->DrawPrimitives(GL_TRIANGLE_FAN, 0, 4); + + Context->ClearVertexBuffer(); // context remove + + glDisable(GL_TEXTURE_2D); + } + + glEnable(GL_DEPTH_TEST); + glDepthMask(GL_TRUE); +} + +void lcModel::SaveStepImages(const QString& BaseName, int Width, int Height, lcStep Start, lcStep End) +{ + gMainWindow->mPreviewWidget->MakeCurrent(); + lcContext* Context = gMainWindow->mPreviewWidget->mContext; + + if (!Context->BeginRenderToTexture(Width, Height)) + { + QMessageBox::warning(gMainWindow, tr("LeoCAD"), tr("Error creating images.")); + return; + } + + lcStep CurrentStep = mCurrentStep; + + View View(this); + View.SetCamera(gMainWindow->GetActiveView()->mCamera, false); + View.mWidth = Width; + View.mHeight = Height; + View.SetContext(Context); + + for (lcStep Step = Start; Step <= End; Step++) + { + SetTemporaryStep(Step); + View.OnDraw(); + + QString FileName = BaseName.arg(Step, 2, 10, QLatin1Char('0')); + + if (!Context->SaveRenderToTextureImage(FileName, Width, Height)) + break; + } + + Context->EndRenderToTexture(); + + SetTemporaryStep(CurrentStep); + + if (!mActive) + CalculateStep(LC_STEP_MAX); +} + +void lcModel::UpdateBackgroundTexture() +{ + lcReleaseTexture(mBackgroundTexture); + mBackgroundTexture = NULL; + + if (mProperties.mBackgroundType == LC_BACKGROUND_IMAGE) + { + mBackgroundTexture = lcLoadTexture(mProperties.mBackgroundImage, LC_TEXTURE_WRAPU | LC_TEXTURE_WRAPV); + + if (!mBackgroundTexture) + mProperties.mBackgroundType = LC_BACKGROUND_SOLID; + } +} + +void lcModel::RayTest(lcObjectRayTest& ObjectRayTest) const +{ + for (int PieceIdx = 0; PieceIdx < mPieces.GetSize(); PieceIdx++) + { + lcPiece* Piece = mPieces[PieceIdx]; + + if (Piece->IsVisible(mCurrentStep)) + Piece->RayTest(ObjectRayTest); + } + + if (ObjectRayTest.PiecesOnly) + return; + + for (int CameraIdx = 0; CameraIdx < mCameras.GetSize(); CameraIdx++) + { + lcCamera* Camera = mCameras[CameraIdx]; + + if (Camera != ObjectRayTest.ViewCamera && Camera->IsVisible()) + Camera->RayTest(ObjectRayTest); + } + + for (int LightIdx = 0; LightIdx < mLights.GetSize(); LightIdx++) + if (mLights[LightIdx]->IsVisible()) + mLights[LightIdx]->RayTest(ObjectRayTest); +} + +void lcModel::BoxTest(lcObjectBoxTest& ObjectBoxTest) const +{ + for (int PieceIdx = 0; PieceIdx < mPieces.GetSize(); PieceIdx++) + { + lcPiece* Piece = mPieces[PieceIdx]; + + if (Piece->IsVisible(mCurrentStep)) + Piece->BoxTest(ObjectBoxTest); + } + + for (int CameraIdx = 0; CameraIdx < mCameras.GetSize(); CameraIdx++) + { + lcCamera* Camera = mCameras[CameraIdx]; + + if (Camera != ObjectBoxTest.ViewCamera && Camera->IsVisible()) + Camera->BoxTest(ObjectBoxTest); + } + + for (int LightIdx = 0; LightIdx < mLights.GetSize(); LightIdx++) + if (mLights[LightIdx]->IsVisible()) + mLights[LightIdx]->BoxTest(ObjectBoxTest); +} + +bool lcModel::SubModelMinIntersectDist(const lcVector3& WorldStart, const lcVector3& WorldEnd, float& MinDistance) const +{ + bool MinIntersect = false; + + for (int PieceIdx = 0; PieceIdx < mPieces.GetSize(); PieceIdx++) + { + lcPiece* Piece = mPieces[PieceIdx]; + + lcMatrix44 InverseWorldMatrix = lcMatrix44AffineInverse(Piece->mModelWorld); + lcVector3 Start = lcMul31(WorldStart, InverseWorldMatrix); + lcVector3 End = lcMul31(WorldEnd, InverseWorldMatrix); + + if (Piece->GetStepHide() == LC_STEP_MAX && Piece->mPieceInfo->MinIntersectDist(Start, End, MinDistance)) // todo: this should check for piece->mMesh first + MinIntersect = true; + } + + return MinIntersect; +} + +bool lcModel::SubModelBoxTest(const lcVector4 Planes[6]) const +{ + for (int PieceIdx = 0; PieceIdx < mPieces.GetSize(); PieceIdx++) + { + lcPiece* Piece = mPieces[PieceIdx]; + + if (Piece->GetStepHide() != LC_STEP_MAX) + continue; + + if (Piece->mPieceInfo->BoxTest(Piece->mModelWorld, Planes)) + return true; + } + + return false; +} + +void lcModel::SaveCheckpoint(const QString& Description) +{ + lcModelHistoryEntry* ModelHistoryEntry = new lcModelHistoryEntry(); + + ModelHistoryEntry->Description = Description; + + QTextStream Stream(&ModelHistoryEntry->File); + SaveLDraw(Stream, false); + + mUndoHistory.InsertAt(0, ModelHistoryEntry); + mRedoHistory.DeleteAll(); + + if (!Description.isEmpty()) + { + gMainWindow->UpdateModified(IsModified()); + gMainWindow->UpdateUndoRedo(mUndoHistory.GetSize() > 1 ? mUndoHistory[0]->Description : QString(), !mRedoHistory.IsEmpty() ? mRedoHistory[0]->Description : QString()); + } +} + +void lcModel::LoadCheckPoint(lcModelHistoryEntry* CheckPoint) +{ + DeleteModel(); + + QBuffer Buffer(&CheckPoint->File); + Buffer.open(QIODevice::ReadOnly); + LoadLDraw(Buffer, lcGetActiveProject()); + + gMainWindow->UpdateTimeline(true, false); + gMainWindow->UpdateCameraMenu(); + gMainWindow->UpdateCurrentStep(); + gMainWindow->UpdateSelectedObjects(true); + gMainWindow->UpdateAllViews(); +} + +void lcModel::SetActive(bool Active) +{ + if (Active) + { + CalculateStep(mCurrentStep); + } + else + { + CalculateStep(LC_STEP_MAX); + + strncpy(mPieceInfo->m_strName, mProperties.mName.toLatin1().constData(), sizeof(mPieceInfo->m_strName)); + strupr(mPieceInfo->m_strName); + mPieceInfo->m_strName[sizeof(mPieceInfo->m_strName) - 1] = 0; + strncpy(mPieceInfo->m_strDescription, mProperties.mName.toLatin1().constData(), sizeof(mPieceInfo->m_strDescription)); + mPieceInfo->m_strDescription[sizeof(mPieceInfo->m_strDescription) - 1] = 0; + } + + mActive = Active; +} + +void lcModel::CalculateStep(lcStep Step) +{ + for (int PieceIdx = 0; PieceIdx < mPieces.GetSize(); PieceIdx++) + { + lcPiece* Piece = mPieces[PieceIdx]; + Piece->UpdatePosition(Step); + + if (Piece->IsSelected()) + { + if (!Piece->IsVisible(Step)) + Piece->SetSelected(false); + else + SelectGroup(Piece->GetTopGroup(), true); + } + } + + for (int CameraIdx = 0; CameraIdx < mCameras.GetSize(); CameraIdx++) + mCameras[CameraIdx]->UpdatePosition(Step); + + for (int LightIdx = 0; LightIdx < mLights.GetSize(); LightIdx++) + mLights[LightIdx]->UpdatePosition(Step); +} + +void lcModel::SetCurrentStep(lcStep Step) +{ + mCurrentStep = Step; + CalculateStep(Step); + + gMainWindow->UpdateTimeline(false, false); + gMainWindow->UpdateSelectedObjects(true); + gMainWindow->UpdateAllViews(); + gMainWindow->UpdateCurrentStep(); +} + +void lcModel::ShowFirstStep() +{ + if (mCurrentStep == 1) + return; + + SetCurrentStep(1); +} + +void lcModel::ShowLastStep() +{ + lcStep LastStep = GetLastStep(); + + if (mCurrentStep == LastStep) + return; + + SetCurrentStep(LastStep); +} + +void lcModel::ShowPreviousStep() +{ + if (mCurrentStep == 1) + return; + + SetCurrentStep(mCurrentStep - 1); +} + +void lcModel::ShowNextStep() +{ + if (mCurrentStep == LC_STEP_MAX) + return; + + SetCurrentStep(mCurrentStep + 1); +} + +lcStep lcModel::GetLastStep() const +{ + lcStep Step = 1; + + for (int PieceIdx = 0; PieceIdx < mPieces.GetSize(); PieceIdx++) + Step = lcMax(Step, mPieces[PieceIdx]->GetStepShow()); + + return Step; +} + +void lcModel::InsertStep(lcStep Step) +{ + for (int PieceIdx = 0; PieceIdx < mPieces.GetSize(); PieceIdx++) + { + lcPiece* Piece = mPieces[PieceIdx]; + Piece->InsertTime(Step, 1); + if (Piece->IsSelected() && !Piece->IsVisible(mCurrentStep)) + Piece->SetSelected(false); + } + + for (int CameraIdx = 0; CameraIdx < mCameras.GetSize(); CameraIdx++) + mCameras[CameraIdx]->InsertTime(Step, 1); + + for (int LightIdx = 0; LightIdx < mLights.GetSize(); LightIdx++) + mLights[LightIdx]->InsertTime(Step, 1); + + SaveCheckpoint(tr("Inserting Step")); + SetCurrentStep(mCurrentStep); +} + +void lcModel::RemoveStep(lcStep Step) +{ + for (int PieceIdx = 0; PieceIdx < mPieces.GetSize(); PieceIdx++) + { + lcPiece* Piece = mPieces[PieceIdx]; + Piece->RemoveTime(Step, 1); + if (Piece->IsSelected() && !Piece->IsVisible(mCurrentStep)) + Piece->SetSelected(false); + } + + for (int CameraIdx = 0; CameraIdx < mCameras.GetSize(); CameraIdx++) + mCameras[CameraIdx]->RemoveTime(Step, 1); + + for (int LightIdx = 0; LightIdx < mLights.GetSize(); LightIdx++) + mLights[LightIdx]->RemoveTime(Step, 1); + + SaveCheckpoint(tr("Removing Step")); + SetCurrentStep(mCurrentStep); +} + +lcGroup* lcModel::AddGroup(const QString& Prefix, lcGroup* Parent) +{ + lcGroup* Group = new lcGroup(); + mGroups.Add(Group); + + Group->mName = GetGroupName(Prefix); + Group->mGroup = Parent; + + return Group; +} + +lcGroup* lcModel::GetGroup(const QString& Name, bool CreateIfMissing) +{ + for (int GroupIdx = 0; GroupIdx < mGroups.GetSize(); GroupIdx++) + { + lcGroup* Group = mGroups[GroupIdx]; + + if (Group->mName == Name) + return Group; + } + + if (CreateIfMissing) + { + lcGroup* Group = new lcGroup(); + Group->mName = Name; + mGroups.Add(Group); + + return Group; + } + + return NULL; +} + +void lcModel::RemoveGroup(lcGroup* Group) +{ + mGroups.Remove(Group); + delete Group; +} + +void lcModel::GroupSelection() +{ + if (!AnyPiecesSelected()) + { + QMessageBox::information(gMainWindow, tr("LeoCAD"), tr("No pieces selected.")); + return; + } + + lcQGroupDialog Dialog(gMainWindow, GetGroupName(tr("Group #"))); + if (Dialog.exec() != QDialog::Accepted) + return; + + lcGroup* NewGroup = GetGroup(Dialog.mName, true); + + for (int PieceIdx = 0; PieceIdx < mPieces.GetSize(); PieceIdx++) + { + lcPiece* Piece = mPieces[PieceIdx]; + + if (Piece->IsSelected()) + { + lcGroup* Group = Piece->GetTopGroup(); + + if (!Group) + Piece->SetGroup(NewGroup); + else if (Group != NewGroup) + Group->mGroup = NewGroup; + } + } + + SaveCheckpoint(tr("Grouping")); +} + +void lcModel::UngroupSelection() +{ + lcArray SelectedGroups; + + for (int PieceIdx = 0; PieceIdx < mPieces.GetSize(); PieceIdx++) + { + lcPiece* Piece = mPieces[PieceIdx]; + + if (Piece->IsSelected()) + { + lcGroup* Group = Piece->GetTopGroup(); + + if (SelectedGroups.FindIndex(Group) == -1) + { + mGroups.Remove(Group); + SelectedGroups.Add(Group); + } + } + } + + for (int PieceIdx = 0; PieceIdx < mPieces.GetSize(); PieceIdx++) + { + lcPiece* Piece = mPieces[PieceIdx]; + lcGroup* Group = Piece->GetGroup(); + + if (SelectedGroups.FindIndex(Group) != -1) + Piece->SetGroup(NULL); + } + + for (int GroupIdx = 0; GroupIdx < mGroups.GetSize(); GroupIdx++) + { + lcGroup* Group = mGroups[GroupIdx]; + + if (SelectedGroups.FindIndex(Group->mGroup) != -1) + Group->mGroup = NULL; + } + + SelectedGroups.DeleteAll(); + + RemoveEmptyGroups(); + SaveCheckpoint(tr("Ungrouping")); +} + +void lcModel::AddSelectedPiecesToGroup() +{ + lcGroup* Group = NULL; + + for (int PieceIdx = 0; PieceIdx < mPieces.GetSize(); PieceIdx++) + { + lcPiece* Piece = mPieces[PieceIdx]; + + if (Piece->IsSelected()) + { + Group = Piece->GetTopGroup(); + if (Group) + break; + } + } + + if (Group) + { + for (int PieceIdx = 0; PieceIdx < mPieces.GetSize(); PieceIdx++) + { + lcPiece* Piece = mPieces[PieceIdx]; + + if (Piece->IsFocused()) + { + Piece->SetGroup(Group); + break; + } + } + } + + RemoveEmptyGroups(); + SaveCheckpoint(tr("Grouping")); +} + +void lcModel::RemoveFocusPieceFromGroup() +{ + for (int PieceIdx = 0; PieceIdx < mPieces.GetSize(); PieceIdx++) + { + lcPiece* Piece = mPieces[PieceIdx]; + + if (Piece->IsFocused()) + { + Piece->SetGroup(NULL); + break; + } + } + + RemoveEmptyGroups(); + SaveCheckpoint(tr("Ungrouping")); +} + +void lcModel::ShowEditGroupsDialog() +{ + QMap PieceParents; + QMap GroupParents; + + for (int PieceIdx = 0; PieceIdx < mPieces.GetSize(); PieceIdx++) + { + lcPiece* Piece = mPieces[PieceIdx]; + PieceParents[Piece] = Piece->GetGroup(); + } + + for (int GroupIdx = 0; GroupIdx < mGroups.GetSize(); GroupIdx++) + { + lcGroup* Group = mGroups[GroupIdx]; + GroupParents[Group] = Group->mGroup; + } + + lcQEditGroupsDialog Dialog(gMainWindow, PieceParents, GroupParents); + + if (Dialog.exec() != QDialog::Accepted) + return; + + bool Modified = Dialog.mNewGroups.isEmpty(); + + for (int PieceIdx = 0; PieceIdx < mPieces.GetSize(); PieceIdx++) + { + lcPiece* Piece = mPieces[PieceIdx]; + lcGroup* ParentGroup = Dialog.mPieceParents.value(Piece); + + if (ParentGroup != Piece->GetGroup()) + { + mPieces[PieceIdx]->SetGroup(ParentGroup); + Modified = true; + } + } + + for (int GroupIdx = 0; GroupIdx < mGroups.GetSize(); GroupIdx++) + { + lcGroup* Group = mGroups[GroupIdx]; + lcGroup* ParentGroup = Dialog.mGroupParents.value(Group); + + if (ParentGroup != Group->mGroup) + { + Group->mGroup = ParentGroup; + Modified = true; + } + } + + if (Modified) + { + ClearSelection(true); + SaveCheckpoint(tr("Editing Groups")); + } +} + +QString lcModel::GetGroupName(const QString& Prefix) +{ + int Length = Prefix.length(); + int Max = 0; + + for (int GroupIdx = 0; GroupIdx < mGroups.GetSize(); GroupIdx++) + { + const QString& Name = mGroups[GroupIdx]->mName; + + if (Name.startsWith(Prefix)) + { + bool Ok = false; + int GroupNumber = Name.mid(Length).toInt(&Ok); + if (Ok && GroupNumber > Max) + Max = GroupNumber; + } + } + + return Prefix + QString::number(Max + 1); +} + +void lcModel::RemoveEmptyGroups() +{ + bool Removed; + + do + { + Removed = false; + + for (int GroupIdx = 0; GroupIdx < mGroups.GetSize();) + { + lcGroup* Group = mGroups[GroupIdx]; + int Ref = 0; + + for (int PieceIdx = 0; PieceIdx < mPieces.GetSize(); PieceIdx++) + if (mPieces[PieceIdx]->GetGroup() == Group) + Ref++; + + for (int ParentIdx = 0; ParentIdx < mGroups.GetSize(); ParentIdx++) + if (mGroups[ParentIdx]->mGroup == Group) + Ref++; + + if (Ref > 1) + { + GroupIdx++; + continue; + } + + if (Ref != 0) + { + for (int PieceIdx = 0; PieceIdx < mPieces.GetSize(); PieceIdx++) + { + lcPiece* Piece = mPieces[PieceIdx]; + + if (Piece->GetGroup() == Group) + { + Piece->SetGroup(Group->mGroup); + break; + } + } + + for (int ParentIdx = 0; ParentIdx < mGroups.GetSize(); ParentIdx++) + { + if (mGroups[ParentIdx]->mGroup == Group) + { + mGroups[ParentIdx]->mGroup = Group->mGroup; + break; + } + } + } + + mGroups.RemoveIndex(GroupIdx); + delete Group; + Removed = true; + } + } + while (Removed); +} + +lcVector3 lcModel::LockVector(const lcVector3& Vector) const +{ + lcVector3 NewVector(Vector); + + if (gMainWindow->GetLockX()) + NewVector[0] = 0; + + if (gMainWindow->GetLockY()) + NewVector[1] = 0; + + if (gMainWindow->GetLockZ()) + NewVector[2] = 0; + + return NewVector; +} + +lcVector3 lcModel::SnapPosition(const lcVector3& Distance) const +{ + lcVector3 NewDistance(Distance); + + float SnapXY = gMainWindow->GetMoveXYSnap(); + if (SnapXY != 0.0f) + { + int i = (int)(NewDistance[0] / SnapXY); + float Leftover = NewDistance[0] - (SnapXY * i); + + if (Leftover > SnapXY / 2) + { + Leftover -= SnapXY; + i++; + } + else if (Leftover < -SnapXY / 2) + { + Leftover += SnapXY; + i--; + } + + NewDistance[0] = SnapXY * i; + + i = (int)(NewDistance[1] / SnapXY); + Leftover = NewDistance[1] - (SnapXY * i); + + if (Leftover > SnapXY / 2) + { + Leftover -= SnapXY; + i++; + } + else if (Leftover < -SnapXY / 2) + { + Leftover += SnapXY; + i--; + } + + NewDistance[1] = SnapXY * i; + } + + float SnapZ = gMainWindow->GetMoveZSnap(); + if (SnapZ != 0.0f) + { + int i = (int)(NewDistance[2] / SnapZ); + float Leftover = NewDistance[2] - (SnapZ * i); + + if (Leftover > SnapZ / 2) + { + Leftover -= SnapZ; + i++; + } + else if (Leftover < -SnapZ / 2) + { + Leftover += SnapZ; + i--; + } + + NewDistance[2] = SnapZ * i; + } + + return NewDistance; +} + +lcVector3 lcModel::SnapRotation(const lcVector3& Angles) const +{ + int AngleSnap = gMainWindow->GetAngleSnap(); + lcVector3 NewAngles(Angles); + + if (AngleSnap) + { + int Snap[3]; + + for (int i = 0; i < 3; i++) + Snap[i] = (int)(Angles[i] / (float)AngleSnap); + + NewAngles = lcVector3((float)(AngleSnap * Snap[0]), (float)(AngleSnap * Snap[1]), (float)(AngleSnap * Snap[2])); + } + + return NewAngles; +} + +lcMatrix33 lcModel::GetRelativeRotation() const +{ + if (gMainWindow->GetRelativeTransform()) + { + lcObject* Focus = GetFocusObject(); + + if (Focus && Focus->IsPiece()) + return ((lcPiece*)Focus)->GetRelativeRotation(); + } + + return lcMatrix33Identity(); +} + +void lcModel::AddPiece() +{ + PieceInfo* CurPiece = gMainWindow->mPreviewWidget->GetCurrentPiece(); + + if (!CurPiece) + return; + + lcPiece* Last = mPieces.IsEmpty() ? NULL : mPieces[mPieces.GetSize() - 1]; + + for (int PieceIdx = 0; PieceIdx < mPieces.GetSize(); PieceIdx++) + { + lcPiece* Piece = mPieces[PieceIdx]; + + if (Piece->IsFocused()) + { + Last = Piece; + break; + } + } + + lcMatrix44 WorldMatrix; + + if (Last) + { + const lcBoundingBox& BoundingBox = Last->GetBoundingBox(); + lcVector3 Dist(0, 0, BoundingBox.Max.z - BoundingBox.Min.z); + Dist = SnapPosition(Dist); + + WorldMatrix = Last->mModelWorld; + WorldMatrix.SetTranslation(lcMul31(Dist, Last->mModelWorld)); + } + else + { + const lcBoundingBox& BoundingBox = CurPiece->GetBoundingBox(); + WorldMatrix = lcMatrix44Translation(lcVector3(0.0f, 0.0f, -BoundingBox.Min.z)); + } + + lcPiece* Piece = new lcPiece(CurPiece); + Piece->Initialize(WorldMatrix, mCurrentStep); + Piece->SetColorIndex(gMainWindow->mColorIndex); + AddPiece(Piece); + gMainWindow->UpdateTimeline(false, false); + ClearSelectionAndSetFocus(Piece, LC_PIECE_SECTION_POSITION); + + SaveCheckpoint("Adding Piece"); +} + +void lcModel::AddPiece(lcPiece* Piece) +{ + for (int PieceIdx = 0; PieceIdx < mPieces.GetSize(); PieceIdx++) + { + if (mPieces[PieceIdx]->GetStepShow() > Piece->GetStepShow()) + { + InsertPiece(Piece, PieceIdx); + return; + } + } + + InsertPiece(Piece, mPieces.GetSize()); +} + +void lcModel::InsertPiece(lcPiece* Piece, int Index) +{ + PieceInfo* Info = Piece->mPieceInfo; + + if (!Info->IsModel()) + { + lcMesh* Mesh = Info->IsTemporary() ? gPlaceholderMesh : Info->GetMesh(); + + if (Mesh->mVertexCacheOffset == -1) + lcGetPiecesLibrary()->mBuffersDirty = true; + } + + mPieces.InsertAt(Index, Piece); +} + +void lcModel::DeleteAllCameras() +{ + if (mCameras.IsEmpty()) + return; + + mCameras.DeleteAll(); + + gMainWindow->UpdateCameraMenu(); + gMainWindow->UpdateSelectedObjects(true); + gMainWindow->UpdateAllViews(); + SaveCheckpoint("Reseting Cameras"); +} + +void lcModel::DeleteSelectedObjects() +{ + if (RemoveSelectedObjects()) + { + gMainWindow->UpdateTimeline(false, false); + gMainWindow->UpdateSelectedObjects(true); + gMainWindow->UpdateAllViews(); + SaveCheckpoint("Deleting"); + } +} + +void lcModel::ResetSelectedPiecesPivotPoint() +{ + for (int PieceIdx = 0; PieceIdx < mPieces.GetSize(); PieceIdx++) + { + lcPiece* Piece = mPieces[PieceIdx]; + + if (Piece->IsSelected()) + Piece->ResetPivotPoint(); + } + + gMainWindow->UpdateAllViews(); +} + +void lcModel::InsertControlPoint() +{ + lcObject* Focus = GetFocusObject(); + + if (!Focus || !Focus->IsPiece()) + return; + + lcPiece* Piece = (lcPiece*)Focus; + + lcVector3 Start, End; + gMainWindow->GetActiveView()->GetRayUnderPointer(Start, End); + + if (Piece->InsertControlPoint(Start, End)) + { + SaveCheckpoint("Modifying"); + gMainWindow->UpdateSelectedObjects(true); + gMainWindow->UpdateAllViews(); + } +} + +void lcModel::RemoveFocusedControlPoint() +{ + lcObject* Focus = GetFocusObject(); + + if (!Focus || !Focus->IsPiece()) + return; + + lcPiece* Piece = (lcPiece*)Focus; + + if (Piece->RemoveFocusedControlPoint()) + { + SaveCheckpoint("Modifying"); + gMainWindow->UpdateSelectedObjects(true); + gMainWindow->UpdateAllViews(); + } +} + +void lcModel::ShowSelectedPiecesEarlier() +{ + lcArray MovedPieces; + + for (int PieceIdx = 0; PieceIdx < mPieces.GetSize(); ) + { + lcPiece* Piece = mPieces[PieceIdx]; + + if (Piece->IsSelected()) + { + lcStep Step = Piece->GetStepShow(); + + if (Step > 1) + { + Step--; + Piece->SetStepShow(Step); + + MovedPieces.Add(Piece); + mPieces.RemoveIndex(PieceIdx); + continue; + } + } + + PieceIdx++; + } + + if (MovedPieces.IsEmpty()) + return; + + for (int PieceIdx = 0; PieceIdx < MovedPieces.GetSize(); PieceIdx++) + { + lcPiece* Piece = MovedPieces[PieceIdx]; + Piece->SetFileLine(-1); + AddPiece(Piece); + } + + SaveCheckpoint("Modifying"); + gMainWindow->UpdateTimeline(false, false); + gMainWindow->UpdateSelectedObjects(true); + gMainWindow->UpdateAllViews(); +} + +void lcModel::ShowSelectedPiecesLater() +{ + lcArray MovedPieces; + + for (int PieceIdx = 0; PieceIdx < mPieces.GetSize(); ) + { + lcPiece* Piece = mPieces[PieceIdx]; + + if (Piece->IsSelected()) + { + lcStep Step = Piece->GetStepShow(); + + if (Step < LC_STEP_MAX) + { + Step++; + Piece->SetStepShow(Step); + + if (!Piece->IsVisible(mCurrentStep)) + Piece->SetSelected(false); + + MovedPieces.Add(Piece); + mPieces.RemoveIndex(PieceIdx); + continue; + } + } + + PieceIdx++; + } + + if (MovedPieces.IsEmpty()) + return; + + for (int PieceIdx = 0; PieceIdx < MovedPieces.GetSize(); PieceIdx++) + { + lcPiece* Piece = MovedPieces[PieceIdx]; + Piece->SetFileLine(-1); + AddPiece(Piece); + } + + SaveCheckpoint("Modifying"); + gMainWindow->UpdateTimeline(false, false); + gMainWindow->UpdateSelectedObjects(true); + gMainWindow->UpdateAllViews(); +} + +void lcModel::SetPieceSteps(const QList>& PieceSteps) +{ + if (PieceSteps.size() != mPieces.GetSize()) + return; + + bool Modified = false; + + for (int PieceIdx = 0; PieceIdx < PieceSteps.size(); PieceIdx++) + { + const QPair& PieceStep = PieceSteps[PieceIdx]; + lcPiece* Piece = mPieces[PieceIdx]; + + if (Piece != PieceStep.first || Piece->GetStepShow() != PieceStep.second) + { + Piece = PieceStep.first; + lcStep Step = PieceStep.second; + + mPieces[PieceIdx] = Piece; + Piece->SetStepShow(Step); + + if (!Piece->IsVisible(mCurrentStep)) + Piece->SetSelected(false); + + Modified = true; + } + } + + if (Modified) + { + SaveCheckpoint("Modifying"); + gMainWindow->UpdateAllViews(); + gMainWindow->UpdateTimeline(false, false); + gMainWindow->UpdateSelectedObjects(true); + } +} + +void lcModel::MoveSelectionToModel(lcModel* Model) +{ + if (!Model) + return; + + lcArray Pieces; + lcPiece* ModelPiece = NULL; + + for (int PieceIdx = 0; PieceIdx < mPieces.GetSize(); ) + { + lcPiece* Piece = mPieces[PieceIdx]; + + if (Piece->IsSelected()) + { + mPieces.RemoveIndex(PieceIdx); + Piece->SetGroup(NULL); // todo: copy groups + Pieces.Add(Piece); + + if (!ModelPiece) + { + ModelPiece = new lcPiece(Model->mPieceInfo); + ModelPiece->Initialize(lcMatrix44Identity(), Piece->GetStepShow()); + ModelPiece->SetColorIndex(gDefaultColor); + InsertPiece(ModelPiece, PieceIdx); + PieceIdx++; + } + } + else + PieceIdx++; + } + + for (int PieceIdx = 0; PieceIdx < Pieces.GetSize(); PieceIdx++) + Model->AddPiece(Pieces[PieceIdx]); + + lcArray UpdatedModels; + Model->UpdatePieceInfo(UpdatedModels); + ModelPiece->UpdatePosition(mCurrentStep); + + SaveCheckpoint("New Model"); + gMainWindow->UpdateTimeline(false, false); + ClearSelectionAndSetFocus(ModelPiece, LC_PIECE_SECTION_POSITION); +} + +void lcModel::InlineAllModels() +{ + for (;;) + { + bool Inlined = false; + + for (int PieceIdx = 0; PieceIdx < mPieces.GetSize(); ) + { + lcPiece* Piece = mPieces[PieceIdx]; + + if (!Piece->mPieceInfo->IsModel()) + { + PieceIdx++; + continue; + } + + mPieces.RemoveIndex(PieceIdx); + + lcArray ModelParts; + Piece->mPieceInfo->GetModelParts(Piece->mModelWorld, Piece->mColorIndex, ModelParts); + + for (int InsertIdx = 0; InsertIdx < ModelParts.GetSize(); InsertIdx++) + { + lcModelPartsEntry& Entry = ModelParts[InsertIdx]; + + lcPiece* NewPiece = new lcPiece(Entry.Info); + + NewPiece->Initialize(Entry.WorldMatrix, Piece->GetStepShow()); + NewPiece->SetColorIndex(Entry.ColorIndex); + NewPiece->UpdatePosition(mCurrentStep); + + InsertPiece(NewPiece, PieceIdx); + PieceIdx++; + } + + delete Piece; + Inlined = true; + } + + if (!Inlined) + break; + } +} + +void lcModel::InlineSelectedModels() +{ + lcArray NewPieces; + + for (int PieceIdx = 0; PieceIdx < mPieces.GetSize(); ) + { + lcPiece* Piece = mPieces[PieceIdx]; + + if (!Piece->IsSelected() || !Piece->mPieceInfo->IsModel()) + { + PieceIdx++; + continue; + } + + mPieces.RemoveIndex(PieceIdx); + + lcArray ModelParts; + Piece->mPieceInfo->GetModelParts(Piece->mModelWorld, Piece->mColorIndex, ModelParts); + + for (int InsertIdx = 0; InsertIdx < ModelParts.GetSize(); InsertIdx++) + { + lcModelPartsEntry& Entry = ModelParts[InsertIdx]; + + lcPiece* NewPiece = new lcPiece(Entry.Info); + + // todo: recreate in groups in the current model + + NewPiece->Initialize(Entry.WorldMatrix, Piece->GetStepShow()); + NewPiece->SetColorIndex(Entry.ColorIndex); + NewPiece->UpdatePosition(mCurrentStep); + + NewPieces.Add(NewPiece); + InsertPiece(NewPiece, PieceIdx); + PieceIdx++; + } + + delete Piece; + } + + if (!NewPieces.GetSize()) + { + QMessageBox::information(gMainWindow, tr("LeoCAD"), tr("No models selected.")); + return; + } + + SaveCheckpoint("Inlining"); + gMainWindow->UpdateTimeline(false, false); + SetSelectionAndFocus(NewPieces, NULL, 0); +} + +bool lcModel::RemoveSelectedObjects() +{ + bool RemovedPiece = false; + bool RemovedCamera = false; + bool RemovedLight = false; + + for (int PieceIdx = 0; PieceIdx < mPieces.GetSize(); ) + { + lcPiece* Piece = mPieces[PieceIdx]; + + if (Piece->IsSelected()) + { + RemovedPiece = true; + mPieces.Remove(Piece); + delete Piece; + } + else + PieceIdx++; + } + + for (int CameraIdx = 0; CameraIdx < mCameras.GetSize(); ) + { + lcCamera* Camera = mCameras[CameraIdx]; + + if (Camera->IsSelected()) + { + const lcArray* Views = gMainWindow->GetViewsForModel(this); + for (int ViewIdx = 0; ViewIdx < Views->GetSize(); ViewIdx++) + { + View* View = (*Views)[ViewIdx]; + + if (Camera == View->mCamera) + View->SetCamera(Camera, true); + } + + RemovedCamera = true; + mCameras.RemoveIndex(CameraIdx); + delete Camera; + } + else + CameraIdx++; + } + + if (RemovedCamera) + gMainWindow->UpdateCameraMenu(); + + for (int LightIdx = 0; LightIdx < mLights.GetSize(); ) + { + lcLight* Light = mLights[LightIdx]; + + if (Light->IsSelected()) + { + RemovedLight = true; + mLights.RemoveIndex(LightIdx); + delete Light; + } + else + LightIdx++; + } + + RemoveEmptyGroups(); + + return RemovedPiece || RemovedCamera || RemovedLight; +} + +void lcModel::MoveSelectedObjects(const lcVector3& PieceDistance, const lcVector3& ObjectDistance, bool Relative, bool AlternateButtonDrag, bool Update, bool Checkpoint) +{ + bool Moved = false; + lcMatrix33 RelativeRotation; + + if (Relative) + RelativeRotation = GetRelativeRotation(); + else + RelativeRotation = lcMatrix33Identity(); + + if (PieceDistance.LengthSquared() >= 0.001f) + { + lcVector3 TransformedPieceDistance = lcMul(PieceDistance, RelativeRotation); + + if (AlternateButtonDrag) + { + for (int PieceIdx = 0; PieceIdx < mPieces.GetSize(); PieceIdx++) + { + lcPiece* Piece = mPieces[PieceIdx]; + + if (Piece->IsFocused()) + { + Piece->MovePivotPoint(TransformedPieceDistance); + Moved = true; + break; + } + } + } + else + { + for (int PieceIdx = 0; PieceIdx < mPieces.GetSize(); PieceIdx++) + { + lcPiece* Piece = mPieces[PieceIdx]; + + if (Piece->IsSelected()) + { + Piece->Move(mCurrentStep, gMainWindow->GetAddKeys(), TransformedPieceDistance); + Piece->UpdatePosition(mCurrentStep); + Moved = true; + } + } + } + } + + if (ObjectDistance.LengthSquared() >= 0.001f && !AlternateButtonDrag) + { + lcVector3 TransformedObjectDistance = lcMul(ObjectDistance, RelativeRotation); + + for (int CameraIdx = 0; CameraIdx < mCameras.GetSize(); CameraIdx++) + { + lcCamera* Camera = mCameras[CameraIdx]; + + if (Camera->IsSelected()) + { + Camera->Move(mCurrentStep, gMainWindow->GetAddKeys(), TransformedObjectDistance); + Camera->UpdatePosition(mCurrentStep); + Moved = true; + } + } + + for (int LightIdx = 0; LightIdx < mLights.GetSize(); LightIdx++) + { + lcLight* Light = mLights[LightIdx]; + + if (Light->IsSelected()) + { + Light->Move(mCurrentStep, gMainWindow->GetAddKeys(), TransformedObjectDistance); + Light->UpdatePosition(mCurrentStep); + Moved = true; + } + } + } + + if (Moved && Update) + { + gMainWindow->UpdateAllViews(); + if (Checkpoint) + SaveCheckpoint("Moving"); + gMainWindow->UpdateSelectedObjects(false); + } +} + +void lcModel::RotateSelectedPieces(const lcVector3& Angles, bool Relative, bool AlternateButtonDrag, bool Update, bool Checkpoint) +{ + if (Angles.LengthSquared() < 0.001f) + return; + + lcMatrix33 RotationMatrix = lcMatrix33Identity(); + bool Rotated = false; + + if (Angles[0] != 0.0f) + RotationMatrix = lcMul(lcMatrix33RotationX(Angles[0] * LC_DTOR), RotationMatrix); + + if (Angles[1] != 0.0f) + RotationMatrix = lcMul(lcMatrix33RotationY(Angles[1] * LC_DTOR), RotationMatrix); + + if (Angles[2] != 0.0f) + RotationMatrix = lcMul(lcMatrix33RotationZ(Angles[2] * LC_DTOR), RotationMatrix); + + if (AlternateButtonDrag) + { + lcObject* Focus = GetFocusObject(); + + if (Focus && Focus->IsPiece()) + { + ((lcPiece*)Focus)->RotatePivotPoint(RotationMatrix); + Rotated = true; + } + } + else + { + lcVector3 Center; + lcMatrix33 RelativeRotation; + + GetMoveRotateTransform(Center, RelativeRotation); + + lcMatrix33 WorldToFocusMatrix; + + if (Relative) + { + WorldToFocusMatrix = lcMatrix33AffineInverse(RelativeRotation); + RotationMatrix = lcMul(RotationMatrix, RelativeRotation); + } + else + WorldToFocusMatrix = lcMatrix33Identity(); + + for (int PieceIdx = 0; PieceIdx < mPieces.GetSize(); PieceIdx++) + { + lcPiece* Piece = mPieces[PieceIdx]; + + if (!Piece->IsSelected()) + continue; + + Piece->Rotate(mCurrentStep, gMainWindow->GetAddKeys(), RotationMatrix, Center, WorldToFocusMatrix); + Piece->UpdatePosition(mCurrentStep); + Rotated = true; + } + } + + if (Rotated && Update) + { + gMainWindow->UpdateAllViews(); + if (Checkpoint) + SaveCheckpoint("Rotating"); + gMainWindow->UpdateSelectedObjects(false); + } +} + +void lcModel::ScaleSelectedPieces(const float Scale, bool Update, bool Checkpoint) +{ + if (Scale < 0.001f) + return; + + lcObject* Focus = GetFocusObject(); + if (!Focus || !Focus->IsPiece()) + return; + + lcPiece* Piece = (lcPiece*)Focus; + lcuint32 Section = Piece->GetFocusSection(); + + if (Section >= LC_PIECE_SECTION_CONTROL_POINT_1 && Section <= LC_PIECE_SECTION_CONTROL_POINT_8) + { + int ControlPointIndex = Section - LC_PIECE_SECTION_CONTROL_POINT_1; + Piece->SetControlPointScale(ControlPointIndex, Scale); + + if (Update) + { + gMainWindow->UpdateAllViews(); + if (Checkpoint) + SaveCheckpoint("Scaling"); + gMainWindow->UpdateSelectedObjects(false); + } + } +} + +void lcModel::TransformSelectedObjects(lcTransformType TransformType, const lcVector3& Transform) +{ + switch (TransformType) + { + case LC_TRANSFORM_ABSOLUTE_TRANSLATION: + MoveSelectedObjects(Transform, false, false, true, true); + break; + + case LC_TRANSFORM_RELATIVE_TRANSLATION: + MoveSelectedObjects(Transform, true, false, true, true); + break; + + case LC_TRANSFORM_ABSOLUTE_ROTATION: + RotateSelectedPieces(Transform, false, false, true, true); + break; + + case LC_TRANSFORM_RELATIVE_ROTATION: + RotateSelectedPieces(Transform, true, false, true, true); + break; + } +} + +void lcModel::SetSelectedPiecesColorIndex(int ColorIndex) +{ + bool Modified = false; + + for (int PieceIdx = 0; PieceIdx < mPieces.GetSize(); PieceIdx++) + { + lcPiece* Piece = mPieces[PieceIdx]; + + if (Piece->IsSelected() && Piece->mColorIndex != ColorIndex) + { + Piece->SetColorIndex(ColorIndex); + Modified = true; + } + } + + if (Modified) + { + SaveCheckpoint(tr("Painting")); + gMainWindow->UpdateSelectedObjects(false); + gMainWindow->UpdateAllViews(); + gMainWindow->UpdateTimeline(false, true); + } +} + +void lcModel::SetSelectedPiecesPieceInfo(PieceInfo* Info) +{ + bool Modified = false; + + for (int PieceIdx = 0; PieceIdx < mPieces.GetSize(); PieceIdx++) + { + lcPiece* Piece = mPieces[PieceIdx]; + + if (Piece->IsSelected() && Piece->mPieceInfo != Info) + { + Piece->mPieceInfo->Release(true); + Piece->SetPieceInfo(Info); + Modified = true; + } + } + + if (Modified) + { + SaveCheckpoint(tr("Setting Part")); + gMainWindow->UpdateSelectedObjects(false); + gMainWindow->UpdateAllViews(); + gMainWindow->UpdateTimeline(false, true); + } +} + +void lcModel::SetSelectedPiecesStepShow(lcStep Step) +{ + bool Modified = false; + bool SelectionChanged = false; + + for (int PieceIdx = 0; PieceIdx < mPieces.GetSize(); PieceIdx++) + { + lcPiece* Piece = mPieces[PieceIdx]; + + if (Piece->IsSelected() && Piece->GetStepShow() != Step) + { + Piece->SetStepShow(Step); + + if (!Piece->IsVisible(mCurrentStep)) + { + Piece->SetSelected(false); + SelectionChanged = true; + } + + Modified = true; + } + } + + if (Modified) + { + SaveCheckpoint(tr("Showing Pieces")); + gMainWindow->UpdateAllViews(); + gMainWindow->UpdateTimeline(false, false); + gMainWindow->UpdateSelectedObjects(SelectionChanged); + } +} + +void lcModel::SetSelectedPiecesStepHide(lcStep Step) +{ + bool Modified = false; + bool SelectionChanged = false; + + for (int PieceIdx = 0; PieceIdx < mPieces.GetSize(); PieceIdx++) + { + lcPiece* Piece = mPieces[PieceIdx]; + + if (Piece->IsSelected() && Piece->GetStepHide() != Step) + { + Piece->SetStepHide(Step); + + if (!Piece->IsVisible(mCurrentStep)) + { + Piece->SetSelected(false); + SelectionChanged = true; + } + + Modified = true; + } + } + + if (Modified) + { + SaveCheckpoint(tr("Hiding Pieces")); + gMainWindow->UpdateAllViews(); + gMainWindow->UpdateTimeline(false, false); + gMainWindow->UpdateSelectedObjects(SelectionChanged); + } +} + +void lcModel::SetCameraOrthographic(lcCamera* Camera, bool Ortho) +{ + if (Camera->IsOrtho() == Ortho) + return; + + Camera->SetOrtho(Ortho); + Camera->UpdatePosition(mCurrentStep); + + SaveCheckpoint(tr("Editing Camera")); + gMainWindow->UpdateAllViews(); + gMainWindow->UpdatePerspective(); +} + +void lcModel::SetCameraFOV(lcCamera* Camera, float FOV) +{ + if (Camera->m_fovy == FOV) + return; + + Camera->m_fovy = FOV; + Camera->UpdatePosition(mCurrentStep); + + SaveCheckpoint(tr("Changing FOV")); + gMainWindow->UpdateAllViews(); +} + +void lcModel::SetCameraZNear(lcCamera* Camera, float ZNear) +{ + if (Camera->m_zNear == ZNear) + return; + + Camera->m_zNear = ZNear; + Camera->UpdatePosition(mCurrentStep); + + SaveCheckpoint(tr("Editing Camera")); + gMainWindow->UpdateAllViews(); +} + +void lcModel::SetCameraZFar(lcCamera* Camera, float ZFar) +{ + if (Camera->m_zFar == ZFar) + return; + + Camera->m_zFar = ZFar; + Camera->UpdatePosition(mCurrentStep); + + SaveCheckpoint(tr("Editing Camera")); + gMainWindow->UpdateAllViews(); +} + +void lcModel::SetCameraName(lcCamera* Camera, const char* Name) +{ + if (!strcmp(Camera->m_strName, Name)) + return; + + strncpy(Camera->m_strName, Name, sizeof(Camera->m_strName)); + Camera->m_strName[sizeof(Camera->m_strName) - 1] = 0; + + SaveCheckpoint(tr("Renaming Camera")); + gMainWindow->UpdateSelectedObjects(false); + gMainWindow->UpdateAllViews(); + gMainWindow->UpdateCameraMenu(); +} + +bool lcModel::AnyPiecesSelected() const +{ + for (int PieceIdx = 0; PieceIdx < mPieces.GetSize(); PieceIdx++) + if (mPieces[PieceIdx]->IsSelected()) + return true; + + return false; +} + +bool lcModel::AnyObjectsSelected() const +{ + for (int PieceIdx = 0; PieceIdx < mPieces.GetSize(); PieceIdx++) + if (mPieces[PieceIdx]->IsSelected()) + return true; + + for (int CameraIdx = 0; CameraIdx < mCameras.GetSize(); CameraIdx++) + if (mCameras[CameraIdx]->IsSelected()) + return true; + + for (int LightIdx = 0; LightIdx < mLights.GetSize(); LightIdx++) + if (mLights[LightIdx]->IsSelected()) + return true; + + return false; +} + +lcObject* lcModel::GetFocusObject() const +{ + for (int PieceIdx = 0; PieceIdx < mPieces.GetSize(); PieceIdx++) + { + lcPiece* Piece = mPieces[PieceIdx]; + + if (Piece->IsFocused()) + return Piece; + } + + for (int CameraIdx = 0; CameraIdx < mCameras.GetSize(); CameraIdx++) + { + lcCamera* Camera = mCameras[CameraIdx]; + + if (Camera->IsFocused()) + return Camera; + } + + for (int LightIdx = 0; LightIdx < mLights.GetSize(); LightIdx++) + { + lcLight* Light = mLights[LightIdx]; + + if (Light->IsFocused()) + return Light; + } + + return NULL; +} + +lcModel* lcModel::GetFirstSelectedSubmodel() const +{ + for (int PieceIdx = 0; PieceIdx < mPieces.GetSize(); PieceIdx++) + { + lcPiece* Piece = mPieces[PieceIdx]; + + if (Piece->IsSelected() && Piece->mPieceInfo->IsModel()) + return Piece->mPieceInfo->GetModel(); + } + + return NULL; +} + +void lcModel::GetSubModels(lcArray SubModels) const +{ + for (int PieceIdx = 0; PieceIdx < mPieces.GetSize(); PieceIdx++) + { + lcPiece* Piece = mPieces[PieceIdx]; + + if (Piece->mPieceInfo->IsModel()) + { + lcModel* SubModel = Piece->mPieceInfo->GetModel(); + if (SubModels.FindIndex(SubModel) != -1) + SubModels.Add(SubModel); + } + } +} + +bool lcModel::GetMoveRotateTransform(lcVector3& Center, lcMatrix33& RelativeRotation) const +{ + bool Relative = gMainWindow->GetRelativeTransform(); + int NumSelected = 0; + + Center = lcVector3(0.0f, 0.0f, 0.0f); + RelativeRotation = lcMatrix33Identity(); + + for (int PieceIdx = 0; PieceIdx < mPieces.GetSize(); PieceIdx++) + { + lcPiece* Piece = mPieces[PieceIdx]; + + if (!Piece->IsSelected()) + continue; + + if (Piece->IsFocused() && Relative) + { + Center = Piece->GetRotationCenter(); + RelativeRotation = Piece->GetRelativeRotation(); + return true; + } + + Center += Piece->mModelWorld.GetTranslation(); + NumSelected++; + } + + for (int CameraIdx = 0; CameraIdx < mCameras.GetSize(); CameraIdx++) + { + lcCamera* Camera = mCameras[CameraIdx]; + + if (!Camera->IsSelected()) + continue; + + if (Camera->IsFocused() && Relative) + { + Center = Camera->GetSectionPosition(Camera->GetFocusSection()); +// RelativeRotation = Piece->GetRelativeRotation(); + return true; + } + + Center += Camera->GetSectionPosition(LC_CAMERA_SECTION_POSITION); + Center += Camera->GetSectionPosition(LC_CAMERA_SECTION_TARGET); + Center += Camera->GetSectionPosition(LC_CAMERA_SECTION_UPVECTOR); + NumSelected += 3; + } + + for (int LightIdx = 0; LightIdx < mLights.GetSize(); LightIdx++) + { + lcLight* Light = mLights[LightIdx]; + + if (!Light->IsSelected()) + continue; + + if (Light->IsFocused() && Relative) + { + Center = Light->GetSectionPosition(Light->GetFocusSection()); +// RelativeRotation = Piece->GetRelativeRotation(); + return true; + } + + Center += Light->GetSectionPosition(LC_LIGHT_SECTION_POSITION); + NumSelected++; + if (Light->IsSpotLight() || Light->IsDirectionalLight()) + { + Center += Light->GetSectionPosition(LC_LIGHT_SECTION_TARGET); + NumSelected++; + } + } + + if (NumSelected) + { + Center /= NumSelected; + return true; + } + + return false; +} + +bool lcModel::GetPieceFocusOrSelectionCenter(lcVector3& Center) const +{ + lcVector3 Min(FLT_MAX, FLT_MAX, FLT_MAX), Max(-FLT_MAX, -FLT_MAX, -FLT_MAX); + lcPiece* Selected = NULL; + int NumSelected = 0; + + for (int PieceIdx = 0; PieceIdx < mPieces.GetSize(); PieceIdx++) + { + lcPiece* Piece = mPieces[PieceIdx]; + + if (Piece->IsFocused()) + { + Center = Piece->mModelWorld.GetTranslation(); + return true; + } + + if (Piece->IsSelected()) + { + Piece->CompareBoundingBox(Min, Max); + Selected = Piece; + NumSelected++; + } + } + + if (NumSelected == 1) + Center = Selected->mModelWorld.GetTranslation(); + else if (NumSelected) + Center = (Min + Max) / 2.0f; + else + Center = lcVector3(0.0f, 0.0f, 0.0f); + + return NumSelected != 0; +} + +lcVector3 lcModel::GetSelectionOrModelCenter() const +{ + lcVector3 Center; + + if (!GetSelectionCenter(Center)) + { + lcVector3 Min(FLT_MAX, FLT_MAX, FLT_MAX), Max(-FLT_MAX, -FLT_MAX, -FLT_MAX); + + if (GetPiecesBoundingBox(Min, Max)) + Center = (Min + Max) / 2.0f; + else + Center = lcVector3(0.0f, 0.0f, 0.0f); + } + + return Center; +} + +bool lcModel::GetFocusPosition(lcVector3& Position) const +{ + lcObject* FocusObject = GetFocusObject(); + + if (FocusObject) + { + Position = FocusObject->GetSectionPosition(FocusObject->GetFocusSection()); + return true; + } + else + { + Position = lcVector3(0.0f, 0.0f, 0.0f); + return false; + } +} + +bool lcModel::GetSelectionCenter(lcVector3& Center) const +{ + lcVector3 Min(FLT_MAX, FLT_MAX, FLT_MAX), Max(-FLT_MAX, -FLT_MAX, -FLT_MAX); + lcPiece* SelectedPiece = NULL; + bool SinglePieceSelected = true; + bool Selected = false; + + for (int PieceIdx = 0; PieceIdx < mPieces.GetSize(); PieceIdx++) + { + lcPiece* Piece = mPieces[PieceIdx]; + + if (Piece->IsSelected()) + { + Piece->CompareBoundingBox(Min, Max); + Selected = true; + + if (!SelectedPiece) + SelectedPiece = Piece; + else + SinglePieceSelected = false; + } + } + + for (int CameraIdx = 0; CameraIdx < mCameras.GetSize(); CameraIdx++) + { + lcCamera* Camera = mCameras[CameraIdx]; + + if (Camera->IsSelected()) + { + Camera->CompareBoundingBox(Min, Max); + Selected = true; + SinglePieceSelected = false; + } + } + + for (int LightIdx = 0; LightIdx < mLights.GetSize(); LightIdx++) + { + lcLight* Light = mLights[LightIdx]; + + if (Light->IsSelected()) + { + Light->CompareBoundingBox(Min, Max); + Selected = true; + SinglePieceSelected = false; + } + } + + if (SelectedPiece && SinglePieceSelected) + Center = SelectedPiece->GetSectionPosition(LC_PIECE_SECTION_POSITION); + else if (Selected) + Center = (Min + Max) / 2.0f; + else + Center = lcVector3(0.0f, 0.0f, 0.0f); + + return Selected; +} + +bool lcModel::GetPiecesBoundingBox(lcVector3& Min, lcVector3& Max) const +{ + Min = lcVector3(FLT_MAX, FLT_MAX, FLT_MAX); + Max = lcVector3(-FLT_MAX, -FLT_MAX, -FLT_MAX); + + if (mPieces.IsEmpty()) + return false; + + for (int PieceIdx = 0; PieceIdx < mPieces.GetSize(); PieceIdx++) + { + lcPiece* Piece = mPieces[PieceIdx]; + + if (Piece->IsVisible(mCurrentStep)) + Piece->CompareBoundingBox(Min, Max); + } + + return true; +} + +void lcModel::GetPartsList(int DefaultColorIndex, lcArray& PartsList) const +{ + for (int PieceIdx = 0; PieceIdx < mPieces.GetSize(); PieceIdx++) + { + lcPiece* Piece = mPieces[PieceIdx]; + + int ColorIndex = Piece->mColorIndex; + + if (ColorIndex == gDefaultColor) + ColorIndex = DefaultColorIndex; + + int UsedIdx; + + for (UsedIdx = 0; UsedIdx < PartsList.GetSize(); UsedIdx++) + { + if (PartsList[UsedIdx].Info != Piece->mPieceInfo || PartsList[UsedIdx].ColorIndex != ColorIndex) + continue; + + PartsList[UsedIdx].Count++; + break; + } + + if (UsedIdx == PartsList.GetSize()) + Piece->mPieceInfo->GetPartsList(ColorIndex, PartsList); + } +} + +void lcModel::GetPartsListForStep(lcStep Step, int DefaultColorIndex, lcArray& PartsList) const +{ + for (int PieceIdx = 0; PieceIdx < mPieces.GetSize(); PieceIdx++) + { + lcPiece* Piece = mPieces[PieceIdx]; + + if (Piece->GetStepShow() != Step) + continue; + + int ColorIndex = Piece->mColorIndex; + + if (ColorIndex == gDefaultColor) + ColorIndex = DefaultColorIndex; + + int UsedIdx; + + for (UsedIdx = 0; UsedIdx < PartsList.GetSize(); UsedIdx++) + { + if (PartsList[UsedIdx].Info != Piece->mPieceInfo || PartsList[UsedIdx].ColorIndex != ColorIndex) + continue; + + PartsList[UsedIdx].Count++; + break; + } + + if (UsedIdx == PartsList.GetSize()) + Piece->mPieceInfo->GetPartsList(ColorIndex, PartsList); + } +} + +void lcModel::GetModelParts(const lcMatrix44& WorldMatrix, int DefaultColorIndex, lcArray& ModelParts) const +{ + for (int PieceIdx = 0; PieceIdx < mPieces.GetSize(); PieceIdx++) + { + lcPiece* Piece = mPieces[PieceIdx]; + + int ColorIndex = Piece->mColorIndex; + + if (ColorIndex == gDefaultColor) + ColorIndex = DefaultColorIndex; + + Piece->mPieceInfo->GetModelParts(lcMul(Piece->mModelWorld, WorldMatrix), ColorIndex, ModelParts); + } +} + +void lcModel::GetSelectionInformation(int* Flags, lcArray& Selection, lcObject** Focus) const +{ + *Flags = 0; + *Focus = NULL; + + if (mPieces.IsEmpty()) + *Flags |= LC_SEL_NO_PIECES; + else + { + lcGroup* Group = NULL; + bool First = true; + + for (int PieceIdx = 0; PieceIdx < mPieces.GetSize(); PieceIdx++) + { + lcPiece* Piece = mPieces[PieceIdx]; + + if (Piece->IsSelected()) + { + Selection.Add(Piece); + + if (Piece->IsFocused()) + *Focus = Piece; + + if (Piece->mPieceInfo->IsModel()) + *Flags |= LC_SEL_MODEL_SELECTED; + + if (Piece->IsHidden()) + *Flags |= LC_SEL_HIDDEN | LC_SEL_HIDDEN_SELECTED; + else + *Flags |= LC_SEL_VISIBLE_SELECTED; + + *Flags |= LC_SEL_PIECE | LC_SEL_SELECTED; + + lcSynthInfo* SynthInfo = Piece->mPieceInfo->GetSynthInfo(); + if (SynthInfo && SynthInfo->CanAddControlPoints()) + { + *Flags |= LC_SEL_CAN_ADD_CONTROL_POINT; + + lcuint32 Section = Piece->GetFocusSection(); + + if (Section >= LC_PIECE_SECTION_CONTROL_POINT_1 && Section <= LC_PIECE_SECTION_CONTROL_POINT_8 && Piece->GetControlPoints().GetSize() > 2) + *Flags |= LC_SEL_CAN_REMOVE_CONTROL_POINT; + } + + if (Piece->GetGroup() != NULL) + { + *Flags |= LC_SEL_GROUPED; + if (Piece->IsFocused()) + *Flags |= LC_SEL_FOCUS_GROUPED; + } + + if (First) + { + Group = Piece->GetGroup(); + First = false; + } + else + { + if (Group != Piece->GetGroup()) + *Flags |= LC_SEL_CAN_GROUP; + else + if (Group == NULL) + *Flags |= LC_SEL_CAN_GROUP; + } + } + else + { + *Flags |= LC_SEL_UNSELECTED; + + if (Piece->IsHidden()) + *Flags |= LC_SEL_HIDDEN; + } + } + } + + for (int CameraIdx = 0; CameraIdx < mCameras.GetSize(); CameraIdx++) + { + lcCamera* Camera = mCameras[CameraIdx]; + + if (Camera->IsSelected()) + { + Selection.Add(Camera); + *Flags |= LC_SEL_SELECTED; + + if (Camera->IsFocused()) + *Focus = Camera; + } + } + + for (int LightIdx = 0; LightIdx < mLights.GetSize(); LightIdx++) + { + lcLight* Light = mLights[LightIdx]; + + if (Light->IsSelected()) + { + Selection.Add(Light); + *Flags |= LC_SEL_SELECTED; + + if (Light->IsFocused()) + *Focus = Light; + } + } +} + +void lcModel::ClearSelection(bool UpdateInterface) +{ + for (int PieceIdx = 0; PieceIdx < mPieces.GetSize(); PieceIdx++) + mPieces[PieceIdx]->SetSelected(false); + + for (int CameraIdx = 0; CameraIdx < mCameras.GetSize(); CameraIdx++) + mCameras[CameraIdx]->SetSelected(false); + + for (int LightIdx = 0; LightIdx < mLights.GetSize(); LightIdx++) + mLights[LightIdx]->SetSelected(false); + + if (UpdateInterface) + { + gMainWindow->UpdateSelectedObjects(true); + gMainWindow->UpdateAllViews(); + } +} + +void lcModel::SelectGroup(lcGroup* TopGroup, bool Select) +{ + if (!TopGroup) + return; + + for (int PieceIdx = 0; PieceIdx < mPieces.GetSize(); PieceIdx++) + { + lcPiece* Piece = mPieces[PieceIdx]; + + if (!Piece->IsSelected() && Piece->IsVisible(mCurrentStep) && (Piece->GetTopGroup() == TopGroup)) + Piece->SetSelected(Select); + } +} + +void lcModel::FocusOrDeselectObject(const lcObjectSection& ObjectSection) +{ + lcObject* FocusObject = GetFocusObject(); + lcObject* Object = ObjectSection.Object; + lcuint32 Section = ObjectSection.Section; + + if (Object) + { + bool WasSelected = Object->IsSelected(); + + if (!Object->IsFocused(Section)) + { + if (FocusObject) + FocusObject->SetFocused(FocusObject->GetFocusSection(), false); + + Object->SetFocused(Section, true); + } + else + Object->SetSelected(Section, false); + + bool IsSelected = Object->IsSelected(); + + if (Object->IsPiece() && (WasSelected != IsSelected)) + SelectGroup(((lcPiece*)Object)->GetTopGroup(), IsSelected); + } + else + { + if (FocusObject) + FocusObject->SetFocused(FocusObject->GetFocusSection(), false); + } + + gMainWindow->UpdateSelectedObjects(true); + gMainWindow->UpdateAllViews(); +} + +void lcModel::ClearSelectionAndSetFocus(lcObject* Object, lcuint32 Section) +{ + ClearSelection(false); + + if (Object) + { + Object->SetFocused(Section, true); + + if (Object->IsPiece()) + SelectGroup(((lcPiece*)Object)->GetTopGroup(), true); + } + + gMainWindow->UpdateSelectedObjects(true); + gMainWindow->UpdateAllViews(); +} + +void lcModel::ClearSelectionAndSetFocus(const lcObjectSection& ObjectSection) +{ + ClearSelectionAndSetFocus(ObjectSection.Object, ObjectSection.Section); +} + +void lcModel::SetSelectionAndFocus(const lcArray& Selection, lcObject* Focus, lcuint32 Section) +{ + ClearSelection(false); + + if (Focus) + { + Focus->SetFocused(Section, true); + + if (Focus->IsPiece()) + SelectGroup(((lcPiece*)Focus)->GetTopGroup(), true); + } + + AddToSelection(Selection); +} + +void lcModel::AddToSelection(const lcArray& Objects) +{ + for (int ObjectIdx = 0; ObjectIdx < Objects.GetSize(); ObjectIdx++) + { + lcObject* Object = Objects[ObjectIdx]; + + bool WasSelected = Object->IsSelected(); + Object->SetSelected(Objects[ObjectIdx]); + + if (!WasSelected && Object->GetType() == LC_OBJECT_PIECE) + SelectGroup(((lcPiece*)Object)->GetTopGroup(), true); + } + + gMainWindow->UpdateSelectedObjects(true); + gMainWindow->UpdateAllViews(); +} + +void lcModel::SelectAllPieces() +{ + for (int PieceIdx = 0; PieceIdx < mPieces.GetSize(); PieceIdx++) + { + lcPiece* Piece = mPieces[PieceIdx]; + + if (Piece->IsVisible(mCurrentStep)) + Piece->SetSelected(true); + } + + gMainWindow->UpdateSelectedObjects(true); + gMainWindow->UpdateAllViews(); +} + +void lcModel::InvertSelection() +{ + for (int PieceIdx = 0; PieceIdx < mPieces.GetSize(); PieceIdx++) + { + lcPiece* Piece = mPieces[PieceIdx]; + + if (Piece->IsVisible(mCurrentStep)) + Piece->SetSelected(!Piece->IsSelected()); + } + + gMainWindow->UpdateSelectedObjects(true); + gMainWindow->UpdateAllViews(); +} + +void lcModel::HideSelectedPieces() +{ + for (int PieceIdx = 0; PieceIdx < mPieces.GetSize(); PieceIdx++) + { + lcPiece* Piece = mPieces[PieceIdx]; + + if (Piece->IsSelected()) + { + Piece->SetHidden(true); + Piece->SetSelected(false); + } + } + + gMainWindow->UpdateTimeline(false, true); + gMainWindow->UpdateSelectedObjects(true); + gMainWindow->UpdateAllViews(); +} + +void lcModel::HideUnselectedPieces() +{ + for (int PieceIdx = 0; PieceIdx < mPieces.GetSize(); PieceIdx++) + { + lcPiece* Piece = mPieces[PieceIdx]; + + if (!Piece->IsSelected()) + Piece->SetHidden(true); + } + + gMainWindow->UpdateTimeline(false, true); + gMainWindow->UpdateSelectedObjects(true); + gMainWindow->UpdateAllViews(); +} + +void lcModel::UnhideSelectedPieces() +{ + for (int PieceIdx = 0; PieceIdx < mPieces.GetSize(); PieceIdx++) + { + lcPiece* Piece = mPieces[PieceIdx]; + + if (Piece->IsSelected()) + Piece->SetHidden(false); + } + + gMainWindow->UpdateTimeline(false, true); + gMainWindow->UpdateSelectedObjects(true); + gMainWindow->UpdateAllViews(); +} + +void lcModel::UnhideAllPieces() +{ + for (int PieceIdx = 0; PieceIdx < mPieces.GetSize(); PieceIdx++) + mPieces[PieceIdx]->SetHidden(false); + + gMainWindow->UpdateTimeline(false, true); + gMainWindow->UpdateSelectedObjects(true); + gMainWindow->UpdateAllViews(); +} + +void lcModel::FindPiece(bool FindFirst, bool SearchForward) +{ + if (mPieces.IsEmpty()) + return; + + int StartIdx = mPieces.GetSize() - 1; + if (!FindFirst) + { + for (int PieceIdx = 0; PieceIdx < mPieces.GetSize(); PieceIdx++) + { + lcPiece* Piece = mPieces[PieceIdx]; + + if (Piece->IsFocused() && Piece->IsVisible(mCurrentStep)) + { + StartIdx = PieceIdx; + break; + } + } + } + + int CurrentIdx = StartIdx; + lcObject* Focus = NULL; + const lcSearchOptions& SearchOptions = gMainWindow->mSearchOptions; + + for (;;) + { + if (SearchForward) + CurrentIdx++; + else + CurrentIdx--; + + if (CurrentIdx < 0) + CurrentIdx = mPieces.GetSize() - 1; + else if (CurrentIdx >= mPieces.GetSize()) + CurrentIdx = 0; + + if (CurrentIdx == StartIdx) + break; + + lcPiece* Current = mPieces[CurrentIdx]; + + if (!Current->IsVisible(mCurrentStep)) + continue; + + if ((!SearchOptions.MatchInfo || Current->mPieceInfo == SearchOptions.Info) && + (!SearchOptions.MatchColor || Current->mColorIndex == SearchOptions.ColorIndex) && + (!SearchOptions.MatchName || strcasestr(Current->GetName(), SearchOptions.Name))) + { + Focus = Current; + break; + } + } + + ClearSelectionAndSetFocus(Focus, LC_PIECE_SECTION_POSITION); +} + +void lcModel::UndoAction() +{ + if (mUndoHistory.GetSize() < 2) + return; + + lcModelHistoryEntry* Undo = mUndoHistory[0]; + mUndoHistory.RemoveIndex(0); + mRedoHistory.InsertAt(0, Undo); + + LoadCheckPoint(mUndoHistory[0]); + + gMainWindow->UpdateModified(IsModified()); + gMainWindow->UpdateUndoRedo(mUndoHistory.GetSize() > 1 ? mUndoHistory[0]->Description : NULL, !mRedoHistory.IsEmpty() ? mRedoHistory[0]->Description : NULL); +} + +void lcModel::RedoAction() +{ + if (mRedoHistory.IsEmpty()) + return; + + lcModelHistoryEntry* Redo = mRedoHistory[0]; + mRedoHistory.RemoveIndex(0); + mUndoHistory.InsertAt(0, Redo); + + LoadCheckPoint(Redo); + + gMainWindow->UpdateModified(IsModified()); + gMainWindow->UpdateUndoRedo(mUndoHistory.GetSize() > 1 ? mUndoHistory[0]->Description : NULL, !mRedoHistory.IsEmpty() ? mRedoHistory[0]->Description : NULL); +} + +void lcModel::BeginMouseTool() +{ + mMouseToolDistance = lcVector3(0.0f, 0.0f, 0.0f); +} + +void lcModel::EndMouseTool(lcTool Tool, bool Accept) +{ + if (!Accept) + { + LoadCheckPoint(mUndoHistory[0]); + return; + } + + switch (Tool) + { + case LC_TOOL_INSERT: + case LC_TOOL_LIGHT: + break; + + case LC_TOOL_SPOTLIGHT: + SaveCheckpoint(tr("New SpotLight")); + break; + + case LC_TOOL_CAMERA: + gMainWindow->UpdateCameraMenu(); + SaveCheckpoint(tr("New Camera")); + break; + + case LC_TOOL_SELECT: + break; + + case LC_TOOL_MOVE: + SaveCheckpoint(tr("Move")); + break; + + case LC_TOOL_ROTATE: + SaveCheckpoint(tr("Rotate")); + break; + + case LC_TOOL_ERASER: + case LC_TOOL_PAINT: + break; + + case LC_TOOL_ZOOM: + if (!gMainWindow->GetActiveView()->mCamera->IsSimple()) + SaveCheckpoint(tr("Zoom")); + break; + + case LC_TOOL_PAN: + if (!gMainWindow->GetActiveView()->mCamera->IsSimple()) + SaveCheckpoint(tr("Pan")); + break; + + case LC_TOOL_ROTATE_VIEW: + if (!gMainWindow->GetActiveView()->mCamera->IsSimple()) + SaveCheckpoint(tr("Orbit")); + break; + + case LC_TOOL_ROLL: + if (!gMainWindow->GetActiveView()->mCamera->IsSimple()) + SaveCheckpoint(tr("Roll")); + break; + + case LC_TOOL_ZOOM_REGION: + break; + + case LC_NUM_TOOLS: + break; + } +} + +void lcModel::InsertPieceToolClicked(const lcMatrix44& WorldMatrix) +{ + lcPiece* Piece = new lcPiece(gMainWindow->mPreviewWidget->GetCurrentPiece()); + Piece->Initialize(WorldMatrix, mCurrentStep); + Piece->SetColorIndex(gMainWindow->mColorIndex); + Piece->UpdatePosition(mCurrentStep); + AddPiece(Piece); + + gMainWindow->UpdateTimeline(false, false); + ClearSelectionAndSetFocus(Piece, LC_PIECE_SECTION_POSITION); + + SaveCheckpoint(tr("Insert")); +} + +void lcModel::PointLightToolClicked(const lcVector3& Position) +{ + lcLight* Light = new lcLight(Position[0], Position[1], Position[2]); + Light->CreateName(mLights); + mLights.Add(Light); + + ClearSelectionAndSetFocus(Light, LC_LIGHT_SECTION_POSITION); + SaveCheckpoint(tr("New Light")); +} + +void lcModel::BeginSpotLightTool(const lcVector3& Position, const lcVector3& Target) +{ + lcLight* Light = new lcLight(Position[0], Position[1], Position[2], Target[0], Target[1], Target[2]); + mLights.Add(Light); + + mMouseToolDistance = Target; + + ClearSelectionAndSetFocus(Light, LC_LIGHT_SECTION_TARGET); +} + +void lcModel::UpdateSpotLightTool(const lcVector3& Position) +{ + lcLight* Light = mLights[mLights.GetSize() - 1]; + + Light->Move(1, false, Position - mMouseToolDistance); + Light->UpdatePosition(1); + + mMouseToolDistance = Position; + + gMainWindow->UpdateSelectedObjects(false); + gMainWindow->UpdateAllViews(); +} + +void lcModel::BeginCameraTool(const lcVector3& Position, const lcVector3& Target) +{ + lcCamera* Camera = new lcCamera(Position[0], Position[1], Position[2], Target[0], Target[1], Target[2]); + Camera->CreateName(mCameras); + mCameras.Add(Camera); + + mMouseToolDistance = Position; + + ClearSelectionAndSetFocus(Camera, LC_CAMERA_SECTION_TARGET); +} + +void lcModel::UpdateCameraTool(const lcVector3& Position) +{ + lcCamera* Camera = mCameras[mCameras.GetSize() - 1]; + + Camera->Move(1, false, Position - mMouseToolDistance); + Camera->UpdatePosition(1); + + mMouseToolDistance = Position; + + gMainWindow->UpdateSelectedObjects(false); + gMainWindow->UpdateAllViews(); +} + +void lcModel::UpdateMoveTool(const lcVector3& Distance, bool AlternateButtonDrag) +{ + lcVector3 PieceDistance = LockVector(SnapPosition(Distance) - SnapPosition(mMouseToolDistance)); + lcVector3 ObjectDistance = Distance - mMouseToolDistance; + + MoveSelectedObjects(PieceDistance, ObjectDistance, true, AlternateButtonDrag, true, false); + mMouseToolDistance = Distance; + + gMainWindow->UpdateSelectedObjects(false); + gMainWindow->UpdateAllViews(); +} + +void lcModel::UpdateRotateTool(const lcVector3& Angles, bool AlternateButtonDrag) +{ + lcVector3 Delta = LockVector(SnapRotation(Angles) - SnapRotation(mMouseToolDistance)); + RotateSelectedPieces(Delta, true, AlternateButtonDrag, false, false); + mMouseToolDistance = Angles; + + gMainWindow->UpdateSelectedObjects(false); + gMainWindow->UpdateAllViews(); +} + +void lcModel::UpdateScaleTool(const float Scale) +{ + ScaleSelectedPieces(Scale, true, false); + + gMainWindow->UpdateSelectedObjects(false); + gMainWindow->UpdateAllViews(); +} + +void lcModel::EraserToolClicked(lcObject* Object) +{ + if (!Object) + return; + + switch (Object->GetType()) + { + case LC_OBJECT_PIECE: + mPieces.Remove((lcPiece*)Object); + RemoveEmptyGroups(); + break; + + case LC_OBJECT_CAMERA: + { + const lcArray* Views = gMainWindow->GetViewsForModel(this); + for (int ViewIdx = 0; ViewIdx < Views->GetSize(); ViewIdx++) + { + View* View = (*Views)[ViewIdx]; + lcCamera* Camera = View->mCamera; + + if (Camera == Object) + View->SetCamera(Camera, true); + } + + mCameras.Remove((lcCamera*)Object); + + gMainWindow->UpdateCameraMenu(); + } + break; + + case LC_OBJECT_LIGHT: + mLights.Remove((lcLight*)Object); + break; + } + + delete Object; + gMainWindow->UpdateTimeline(false, false); + gMainWindow->UpdateSelectedObjects(true); + gMainWindow->UpdateAllViews(); + SaveCheckpoint(tr("Deleting")); +} + +void lcModel::PaintToolClicked(lcObject* Object) +{ + if (!Object || Object->GetType() != LC_OBJECT_PIECE) + return; + + lcPiece* Piece = (lcPiece*)Object; + + if (Piece->mColorIndex != gMainWindow->mColorIndex) + { + Piece->SetColorIndex(gMainWindow->mColorIndex); + + SaveCheckpoint(tr("Painting")); + gMainWindow->UpdateSelectedObjects(false); + gMainWindow->UpdateAllViews(); + gMainWindow->UpdateTimeline(false, true); + } +} + +void lcModel::UpdateZoomTool(lcCamera* Camera, float Mouse) +{ + Camera->Zoom(Mouse - mMouseToolDistance.x, mCurrentStep, gMainWindow->GetAddKeys()); + mMouseToolDistance.x = Mouse; + gMainWindow->UpdateAllViews(); +} + +void lcModel::UpdatePanTool(lcCamera* Camera, const lcVector3& Distance) +{ + Camera->Pan(Distance - mMouseToolDistance, mCurrentStep, gMainWindow->GetAddKeys()); + mMouseToolDistance = Distance; + gMainWindow->UpdateAllViews(); +} + +void lcModel::UpdateOrbitTool(lcCamera* Camera, float MouseX, float MouseY) +{ + lcVector3 Center; + GetSelectionCenter(Center); + Camera->Orbit(MouseX - mMouseToolDistance.x, MouseY - mMouseToolDistance.y, Center, mCurrentStep, gMainWindow->GetAddKeys()); + mMouseToolDistance.x = MouseX; + mMouseToolDistance.y = MouseY; + gMainWindow->UpdateAllViews(); +} + +void lcModel::UpdateRollTool(lcCamera* Camera, float Mouse) +{ + Camera->Roll(Mouse - mMouseToolDistance.x, mCurrentStep, gMainWindow->GetAddKeys()); + mMouseToolDistance.x = Mouse; + gMainWindow->UpdateAllViews(); +} + +void lcModel::ZoomRegionToolClicked(lcCamera* Camera, float AspectRatio, const lcVector3& Position, const lcVector3& TargetPosition, const lcVector3* Corners) +{ + Camera->ZoomRegion(AspectRatio, Position, TargetPosition, Corners, mCurrentStep, gMainWindow->GetAddKeys()); + + gMainWindow->UpdateSelectedObjects(false); + gMainWindow->UpdateAllViews(); + + if (!Camera->IsSimple()) + SaveCheckpoint(tr("Zoom")); +} + +void lcModel::LookAt(lcCamera* Camera) +{ + lcVector3 Center; + + if (!GetSelectionCenter(Center)) + { + lcVector3 Min(FLT_MAX, FLT_MAX, FLT_MAX), Max(-FLT_MAX, -FLT_MAX, -FLT_MAX); + + if (GetPiecesBoundingBox(Min, Max)) + Center = (Min + Max) / 2.0f; + else + Center = lcVector3(0.0f, 0.0f, 0.0f); + } + + Camera->Center(Center, mCurrentStep, gMainWindow->GetAddKeys()); + + gMainWindow->UpdateSelectedObjects(false); + gMainWindow->UpdateAllViews(); + + if (!Camera->IsSimple()) + SaveCheckpoint(tr("Look At")); +} + +void lcModel::ZoomExtents(lcCamera* Camera, float Aspect) +{ + lcVector3 Min(FLT_MAX, FLT_MAX, FLT_MAX), Max(-FLT_MAX, -FLT_MAX, -FLT_MAX); + + if (!GetPiecesBoundingBox(Min, Max)) + return; + + lcVector3 Center = (Min + Max) / 2.0f; + + lcVector3 Points[8]; + lcGetBoxCorners(Min, Max, Points); + + Camera->ZoomExtents(Aspect, Center, Points, 8, mCurrentStep, gMainWindow->GetAddKeys()); + + gMainWindow->UpdateSelectedObjects(false); + gMainWindow->UpdateAllViews(); + + if (!Camera->IsSimple()) + SaveCheckpoint(tr("Zoom")); +} + +void lcModel::Zoom(lcCamera* Camera, float Amount) +{ + Camera->Zoom(Amount, mCurrentStep, gMainWindow->GetAddKeys()); + gMainWindow->UpdateSelectedObjects(false); + gMainWindow->UpdateAllViews(); + + if (!Camera->IsSimple()) + SaveCheckpoint(tr("Zoom")); +} + +void lcModel::ShowPropertiesDialog() +{ + lcPropertiesDialogOptions Options; + + Options.Properties = mProperties; + Options.SetDefault = false; + + GetPartsList(gDefaultColor, Options.PartsList); + + if (!gMainWindow->DoDialog(LC_DIALOG_PROPERTIES, &Options)) + return; + + if (Options.SetDefault) + Options.Properties.SaveDefaults(); + + if (mProperties == Options.Properties) + return; + + mProperties = Options.Properties; + + UpdateBackgroundTexture(); + + SaveCheckpoint(tr("Changing Properties")); +} + +void lcModel::ShowSelectByNameDialog() +{ + if (mPieces.IsEmpty() && mCameras.IsEmpty() && mLights.IsEmpty()) + { + QMessageBox::information(gMainWindow, tr("LeoCAD"), tr("Nothing to select.")); + return; + } + + lcQSelectDialog Dialog(gMainWindow); + + if (Dialog.exec() != QDialog::Accepted) + return; + + SetSelectionAndFocus(Dialog.mObjects, NULL, 0); +} + +void lcModel::ShowArrayDialog() +{ + lcVector3 Center; + + if (!GetPieceFocusOrSelectionCenter(Center)) + { + QMessageBox::information(gMainWindow, tr("LeoCAD"), tr("No pieces selected.")); + return; + } + + lcQArrayDialog Dialog(gMainWindow); + + if (Dialog.exec() != QDialog::Accepted) + return; + + if (Dialog.mCounts[0] * Dialog.mCounts[1] * Dialog.mCounts[2] < 2) + { + QMessageBox::information(gMainWindow, tr("LeoCAD"), tr("Array only has 1 element or less, no pieces added.")); + return; + } + + lcArray NewPieces; + + for (int Step1 = 0; Step1 < Dialog.mCounts[0]; Step1++) + { + for (int Step2 = 0; Step2 < Dialog.mCounts[1]; Step2++) + { + for (int Step3 = (Step1 == 0 && Step2 == 0) ? 1 : 0; Step3 < Dialog.mCounts[2]; Step3++) + { + lcMatrix44 ModelWorld; + lcVector3 Position; + + lcVector3 RotationAngles = Dialog.mRotations[0] * Step1 + Dialog.mRotations[1] * Step2 + Dialog.mRotations[2] * Step3; + lcVector3 Offset = Dialog.mOffsets[0] * Step1 + Dialog.mOffsets[1] * Step2 + Dialog.mOffsets[2] * Step3; + + for (int PieceIdx = 0; PieceIdx < mPieces.GetSize(); PieceIdx++) + { + lcPiece* Piece = mPieces[PieceIdx]; + + if (!Piece->IsSelected()) + continue; + + ModelWorld = Piece->mModelWorld; + + ModelWorld.r[3] -= lcVector4(Center, 0.0f); + ModelWorld = lcMul(ModelWorld, lcMatrix44RotationX(RotationAngles[0] * LC_DTOR)); + ModelWorld = lcMul(ModelWorld, lcMatrix44RotationY(RotationAngles[1] * LC_DTOR)); + ModelWorld = lcMul(ModelWorld, lcMatrix44RotationZ(RotationAngles[2] * LC_DTOR)); + ModelWorld.r[3] += lcVector4(Center, 0.0f); + + Position = lcVector3(ModelWorld.r[3].x, ModelWorld.r[3].y, ModelWorld.r[3].z); + ModelWorld.SetTranslation(Position + Offset); + + lcPiece* NewPiece = new lcPiece(Piece->mPieceInfo); + NewPiece->Initialize(ModelWorld, mCurrentStep); + NewPiece->SetColorIndex(Piece->mColorIndex); + + NewPieces.Add(NewPiece); + } + } + } + } + + for (int PieceIdx = 0; PieceIdx < NewPieces.GetSize(); PieceIdx++) + { + lcPiece* Piece = (lcPiece*)NewPieces[PieceIdx]; + Piece->UpdatePosition(mCurrentStep); + AddPiece(Piece); + } + + AddToSelection(NewPieces); + gMainWindow->UpdateTimeline(false, false); + SaveCheckpoint(tr("Array")); +} + +void lcModel::ShowMinifigDialog() +{ + lcQMinifigDialog Dialog(gMainWindow); + + if (Dialog.exec() != QDialog::Accepted) + return; + + gMainWindow->mPreviewWidget->MakeCurrent(); + + lcGroup* Group = AddGroup(tr("Minifig #"), NULL); + lcArray Pieces(LC_MFW_NUMITEMS); + lcMinifig& Minifig = Dialog.mMinifigWidget->mMinifig; + + for (int PartIdx = 0; PartIdx < LC_MFW_NUMITEMS; PartIdx++) + { + if (Minifig.Parts[PartIdx] == NULL) + continue; + + lcPiece* Piece = new lcPiece(Minifig.Parts[PartIdx]); + + Piece->Initialize(Minifig.Matrices[PartIdx], mCurrentStep); + Piece->SetColorIndex(Minifig.Colors[PartIdx]); + Piece->SetGroup(Group); + AddPiece(Piece); + Piece->UpdatePosition(mCurrentStep); + + Pieces.Add(Piece); + } + + SetSelectionAndFocus(Pieces, NULL, 0); + gMainWindow->UpdateTimeline(false, false); + SaveCheckpoint(tr("Minifig")); +} + +void lcModel::UpdateInterface() +{ + gMainWindow->UpdateTimeline(true, false); + gMainWindow->UpdateUndoRedo(mUndoHistory.GetSize() > 1 ? mUndoHistory[0]->Description : NULL, !mRedoHistory.IsEmpty() ? mRedoHistory[0]->Description : NULL); + gMainWindow->UpdatePaste(!g_App->mClipboard.isEmpty()); + gMainWindow->UpdateCategories(); + gMainWindow->UpdateTitle(); + gMainWindow->SetTool(gMainWindow->GetTool()); + + gMainWindow->UpdateSelectedObjects(true); + gMainWindow->SetTransformType(gMainWindow->GetTransformType()); + gMainWindow->UpdateLockSnap(); + gMainWindow->UpdateSnap(); + gMainWindow->UpdateCameraMenu(); + gMainWindow->UpdateModels(); + gMainWindow->UpdatePerspective(); + gMainWindow->UpdateCurrentStep(); +} diff --git a/common/lc_model.h b/common/lc_model.h index deea451f..ff185946 100644 --- a/common/lc_model.h +++ b/common/lc_model.h @@ -1,361 +1,361 @@ -#ifndef _LC_MODEL_H_ -#define _LC_MODEL_H_ - -#include "lc_math.h" -#include "object.h" -#include "lc_commands.h" - -#define LC_SEL_NO_PIECES 0x0001 // No pieces in model -#define LC_SEL_PIECE 0x0002 // At last 1 piece selected -#define LC_SEL_SELECTED 0x0004 // At last 1 object selected -#define LC_SEL_UNSELECTED 0x0008 // At least 1 piece unselected -#define LC_SEL_HIDDEN 0x0010 // At least one piece hidden -#define LC_SEL_HIDDEN_SELECTED 0x0020 // At least one piece selected is hidden -#define LC_SEL_VISIBLE_SELECTED 0x0040 // At least one piece selected is not hidden -#define LC_SEL_GROUPED 0x0080 // At least one piece selected is grouped -#define LC_SEL_FOCUS_GROUPED 0x0100 // Focused piece is grouped -#define LC_SEL_CAN_GROUP 0x0200 // Can make a new group -#define LC_SEL_MODEL_SELECTED 0x0400 // At least one model reference is selected -#define LC_SEL_CAN_ADD_CONTROL_POINT 0x0800 // Can add control points to focused piece -#define LC_SEL_CAN_REMOVE_CONTROL_POINT 0x1000 // Can remove control points from focused piece - -enum lcTransformType -{ - LC_TRANSFORM_ABSOLUTE_TRANSLATION, - LC_TRANSFORM_RELATIVE_TRANSLATION, - LC_TRANSFORM_ABSOLUTE_ROTATION, - LC_TRANSFORM_RELATIVE_ROTATION -}; - -enum lcBackgroundType -{ - LC_BACKGROUND_SOLID, - LC_BACKGROUND_GRADIENT, - LC_BACKGROUND_IMAGE -}; - -class lcModelProperties -{ -public: - void LoadDefaults(); - void SaveDefaults(); - - bool operator==(const lcModelProperties& Properties) - { - if (mName != Properties.mName || mAuthor != Properties.mAuthor || - mDescription != Properties.mDescription || mComments != Properties.mComments) - return false; - - if (mBackgroundType != Properties.mBackgroundType || mBackgroundSolidColor != Properties.mBackgroundSolidColor || - mBackgroundGradientColor1 != Properties.mBackgroundGradientColor1 || mBackgroundGradientColor2 != Properties.mBackgroundGradientColor2 || - mBackgroundImage != Properties.mBackgroundImage || mBackgroundImageTile != Properties.mBackgroundImageTile) - return false; - - if (mFogEnabled != Properties.mFogEnabled || mFogDensity != Properties.mFogDensity || - mFogColor != Properties.mFogColor || mAmbientColor != Properties.mAmbientColor) - return false; - - return true; - } - - void SaveLDraw(QTextStream& Stream) const; - void ParseLDrawLine(QTextStream& Stream); - - QString mName; - QString mAuthor; - QString mDescription; - QString mComments; - - lcBackgroundType mBackgroundType; - lcVector3 mBackgroundSolidColor; - lcVector3 mBackgroundGradientColor1; - lcVector3 mBackgroundGradientColor2; - QString mBackgroundImage; - bool mBackgroundImageTile; - - bool mFogEnabled; - float mFogDensity; - lcVector3 mFogColor; - lcVector3 mAmbientColor; -}; - -struct lcModelHistoryEntry -{ - QByteArray File; - QString Description; -}; - -struct lcPartsListEntry -{ - PieceInfo* Info; - int ColorIndex; - int Count; -}; - -struct lcModelPartsEntry -{ - lcMatrix44 WorldMatrix; - PieceInfo* Info; - int ColorIndex; -}; - -class lcModel -{ -public: - lcModel(const QString& Name); - ~lcModel(); - - bool IsModified() const - { - return mSavedHistory != mUndoHistory[0]; - } - - bool IncludesModel(const lcModel* Model) const; - void CreatePieceInfo(Project* Project); - void UpdatePieceInfo(lcArray& UpdatedModels); - - PieceInfo* GetPieceInfo() const - { - return mPieceInfo; - } - - const lcArray& GetPieces() const - { - return mPieces; - } - - const lcArray& GetCameras() const - { - return mCameras; - } - - const lcArray& GetLights() const - { - return mLights; - } - - const lcArray& GetGroups() const - { - return mGroups; - } - - const lcModelProperties& GetProperties() const - { - return mProperties; - } - - void SetName(const QString& Name) - { - mProperties.mName = Name; - } - - const QStringList& GetFileLines() const - { - return mFileLines; - } - - lcStep GetLastStep() const; - - lcStep GetCurrentStep() const - { - return mCurrentStep; - } - - void SetActive(bool Active); - void CalculateStep(lcStep Step); - void SetCurrentStep(lcStep Step); - void SetTemporaryStep(lcStep Step) - { - mCurrentStep = Step; - CalculateStep(Step); - } - - void ShowFirstStep(); - void ShowLastStep(); - void ShowPreviousStep(); - void ShowNextStep(); - void InsertStep(lcStep Step); - void RemoveStep(lcStep Step); - - void AddPiece(); - void DeleteAllCameras(); - void DeleteSelectedObjects(); - void ResetSelectedPiecesPivotPoint(); - void InsertControlPoint(); - void RemoveFocusedControlPoint(); - void ShowSelectedPiecesEarlier(); - void ShowSelectedPiecesLater(); - void SetPieceSteps(const QList>& PieceSteps); - - void MoveSelectionToModel(lcModel* Model); - void InlineAllModels(); - void InlineSelectedModels(); - - lcGroup* AddGroup(const QString& Prefix, lcGroup* Parent); - lcGroup* GetGroup(const QString& Name, bool CreateIfMissing); - void RemoveGroup(lcGroup* Group); - void GroupSelection(); - void UngroupSelection(); - void AddSelectedPiecesToGroup(); - void RemoveFocusPieceFromGroup(); - void ShowEditGroupsDialog(); - - void SaveLDraw(QTextStream& Stream, bool SelectedOnly) const; - void LoadLDraw(QIODevice& Device, Project* Project); - bool LoadBinary(lcFile* File); - void Merge(lcModel* Other); - - void SetSaved() - { - if (mUndoHistory.IsEmpty()) - SaveCheckpoint(QString()); - - mSavedHistory = mUndoHistory[0]; - } - - void Cut(); - void Copy(); - void Paste(); - - void GetScene(lcScene& Scene, lcCamera* ViewCamera, bool DrawInterface) const; - void SubModelAddRenderMeshes(lcScene& Scene, const lcMatrix44& WorldMatrix, int DefaultColorIndex, bool Focused, bool Selected) const; - void DrawBackground(lcContext* Context); - void SaveStepImages(const QString& BaseName, int Width, int Height, lcStep Start, lcStep End); - - void RayTest(lcObjectRayTest& ObjectRayTest) const; - void BoxTest(lcObjectBoxTest& ObjectBoxTest) const; - bool SubModelMinIntersectDist(const lcVector3& WorldStart, const lcVector3& WorldEnd, float& MinDistance) const; - bool SubModelBoxTest(const lcVector4 Planes[6]) const; - - bool AnyPiecesSelected() const; - bool AnyObjectsSelected() const; - lcModel* GetFirstSelectedSubmodel() const; - void GetSubModels(lcArray SubModels) const; - bool GetMoveRotateTransform(lcVector3& Center, lcMatrix33& RelativeRotation) const; - bool GetPieceFocusOrSelectionCenter(lcVector3& Center) const; - lcVector3 GetSelectionOrModelCenter() const; - bool GetFocusPosition(lcVector3& Position) const; - lcObject* GetFocusObject() const; - bool GetSelectionCenter(lcVector3& Center) const; - bool GetPiecesBoundingBox(lcVector3& Min, lcVector3& Max) const; - void GetPartsList(int DefaultColorIndex, lcArray& PartsList) const; - void GetPartsListForStep(lcStep Step, int DefaultColorIndex, lcArray& PartsList) const; - void GetModelParts(const lcMatrix44& WorldMatrix, int DefaultColorIndex, lcArray& ModelParts) const; - void GetSelectionInformation(int* Flags, lcArray& Selection, lcObject** Focus) const; - - void FocusOrDeselectObject(const lcObjectSection& ObjectSection); - void ClearSelection(bool UpdateInterface); - void ClearSelectionAndSetFocus(lcObject* Object, lcuint32 Section); - void ClearSelectionAndSetFocus(const lcObjectSection& ObjectSection); - void SetSelectionAndFocus(const lcArray& Selection, lcObject* Focus, lcuint32 Section); - void AddToSelection(const lcArray& Objects); - void SelectAllPieces(); - void InvertSelection(); - - void HideSelectedPieces(); - void HideUnselectedPieces(); - void UnhideSelectedPieces(); - void UnhideAllPieces(); - - void FindPiece(bool FindFirst, bool SearchForward); - - void UndoAction(); - void RedoAction(); - - lcVector3 LockVector(const lcVector3& Vector) const; - lcVector3 SnapPosition(const lcVector3& Delta) const; - lcVector3 SnapRotation(const lcVector3& Delta) const; - lcMatrix33 GetRelativeRotation() const; - - const lcVector3& GetMouseToolDistance() const - { - return mMouseToolDistance; - } - - void BeginMouseTool(); - void EndMouseTool(lcTool Tool, bool Accept); - void InsertPieceToolClicked(const lcMatrix44& WorldMatrix); - void PointLightToolClicked(const lcVector3& Position); - void BeginSpotLightTool(const lcVector3& Position, const lcVector3& Target); - void UpdateSpotLightTool(const lcVector3& Position); - void BeginCameraTool(const lcVector3& Position, const lcVector3& Target); - void UpdateCameraTool(const lcVector3& Position); - void UpdateMoveTool(const lcVector3& Distance, bool AlternateButtonDrag); - void UpdateRotateTool(const lcVector3& Angles, bool AlternateButtonDrag); - void UpdateScaleTool(const float Scale); - void EraserToolClicked(lcObject* Object); - void PaintToolClicked(lcObject* Object); - void UpdateZoomTool(lcCamera* Camera, float Mouse); - void UpdatePanTool(lcCamera* Camera, const lcVector3& Distance); - void UpdateOrbitTool(lcCamera* Camera, float MouseX, float MouseY); - void UpdateRollTool(lcCamera* Camera, float Mouse); - void ZoomRegionToolClicked(lcCamera* Camera, float AspectRatio, const lcVector3& Position, const lcVector3& TargetPosition, const lcVector3* Corners); - void LookAt(lcCamera* Camera); - void ZoomExtents(lcCamera* Camera, float Aspect); - void Zoom(lcCamera* Camera, float Amount); - - void MoveSelectedObjects(const lcVector3& Distance, bool Relative, bool AlternateButtonDrag, bool Update, bool Checkpoint) - { - MoveSelectedObjects(Distance, Distance, Relative, AlternateButtonDrag, Update, Checkpoint); - } - - void MoveSelectedObjects(const lcVector3& PieceDistance, const lcVector3& ObjectDistance, bool Relative, bool AlternateButtonDrag, bool Update, bool Checkpoint); - void RotateSelectedPieces(const lcVector3& Angles, bool Relative, bool AlternateButtonDrag, bool Update, bool Checkpoint); - void ScaleSelectedPieces(const float Scale, bool Update, bool Checkpoint); - void TransformSelectedObjects(lcTransformType TransformType, const lcVector3& Transform); - void SetSelectedPiecesColorIndex(int ColorIndex); - void SetSelectedPiecesPieceInfo(PieceInfo* Info); - void SetSelectedPiecesStepShow(lcStep Step); - void SetSelectedPiecesStepHide(lcStep Step); - - void SetCameraOrthographic(lcCamera* Camera, bool Ortho); - void SetCameraFOV(lcCamera* Camera, float FOV); - void SetCameraZNear(lcCamera* Camera, float ZNear); - void SetCameraZFar(lcCamera* Camera, float ZFar); - void SetCameraName(lcCamera* Camera, const char* Name); - - void ShowPropertiesDialog(); - void ShowSelectByNameDialog(); - void ShowArrayDialog(); - void ShowMinifigDialog(); - void UpdateInterface(); - -protected: - void DeleteModel(); - void DeleteHistory(); - void SaveCheckpoint(const QString& Description); - void LoadCheckPoint(lcModelHistoryEntry* CheckPoint); - - QString GetGroupName(const QString& Prefix); - void RemoveEmptyGroups(); - bool RemoveSelectedObjects(); - - void UpdateBackgroundTexture(); - - void SelectGroup(lcGroup* TopGroup, bool Select); - - void AddPiece(lcPiece* Piece); - void InsertPiece(lcPiece* Piece, int Index); - - lcModelProperties mProperties; - PieceInfo* mPieceInfo; - - bool mActive; - lcStep mCurrentStep; - lcVector3 mMouseToolDistance; - lcTexture* mBackgroundTexture; - - lcArray mPieces; - lcArray mCameras; - lcArray mLights; - lcArray mGroups; - QStringList mFileLines; - - lcModelHistoryEntry* mSavedHistory; - lcArray mUndoHistory; - lcArray mRedoHistory; - - Q_DECLARE_TR_FUNCTIONS(lcModel); -}; - -#endif // _LC_MODEL_H_ +#ifndef _LC_MODEL_H_ +#define _LC_MODEL_H_ + +#include "lc_math.h" +#include "object.h" +#include "lc_commands.h" + +#define LC_SEL_NO_PIECES 0x0001 // No pieces in model +#define LC_SEL_PIECE 0x0002 // At last 1 piece selected +#define LC_SEL_SELECTED 0x0004 // At last 1 object selected +#define LC_SEL_UNSELECTED 0x0008 // At least 1 piece unselected +#define LC_SEL_HIDDEN 0x0010 // At least one piece hidden +#define LC_SEL_HIDDEN_SELECTED 0x0020 // At least one piece selected is hidden +#define LC_SEL_VISIBLE_SELECTED 0x0040 // At least one piece selected is not hidden +#define LC_SEL_GROUPED 0x0080 // At least one piece selected is grouped +#define LC_SEL_FOCUS_GROUPED 0x0100 // Focused piece is grouped +#define LC_SEL_CAN_GROUP 0x0200 // Can make a new group +#define LC_SEL_MODEL_SELECTED 0x0400 // At least one model reference is selected +#define LC_SEL_CAN_ADD_CONTROL_POINT 0x0800 // Can add control points to focused piece +#define LC_SEL_CAN_REMOVE_CONTROL_POINT 0x1000 // Can remove control points from focused piece + +enum lcTransformType +{ + LC_TRANSFORM_ABSOLUTE_TRANSLATION, + LC_TRANSFORM_RELATIVE_TRANSLATION, + LC_TRANSFORM_ABSOLUTE_ROTATION, + LC_TRANSFORM_RELATIVE_ROTATION +}; + +enum lcBackgroundType +{ + LC_BACKGROUND_SOLID, + LC_BACKGROUND_GRADIENT, + LC_BACKGROUND_IMAGE +}; + +class lcModelProperties +{ +public: + void LoadDefaults(); + void SaveDefaults(); + + bool operator==(const lcModelProperties& Properties) + { + if (mName != Properties.mName || mAuthor != Properties.mAuthor || + mDescription != Properties.mDescription || mComments != Properties.mComments) + return false; + + if (mBackgroundType != Properties.mBackgroundType || mBackgroundSolidColor != Properties.mBackgroundSolidColor || + mBackgroundGradientColor1 != Properties.mBackgroundGradientColor1 || mBackgroundGradientColor2 != Properties.mBackgroundGradientColor2 || + mBackgroundImage != Properties.mBackgroundImage || mBackgroundImageTile != Properties.mBackgroundImageTile) + return false; + + if (mFogEnabled != Properties.mFogEnabled || mFogDensity != Properties.mFogDensity || + mFogColor != Properties.mFogColor || mAmbientColor != Properties.mAmbientColor) + return false; + + return true; + } + + void SaveLDraw(QTextStream& Stream) const; + void ParseLDrawLine(QTextStream& Stream); + + QString mName; + QString mAuthor; + QString mDescription; + QString mComments; + + lcBackgroundType mBackgroundType; + lcVector3 mBackgroundSolidColor; + lcVector3 mBackgroundGradientColor1; + lcVector3 mBackgroundGradientColor2; + QString mBackgroundImage; + bool mBackgroundImageTile; + + bool mFogEnabled; + float mFogDensity; + lcVector3 mFogColor; + lcVector3 mAmbientColor; +}; + +struct lcModelHistoryEntry +{ + QByteArray File; + QString Description; +}; + +struct lcPartsListEntry +{ + PieceInfo* Info; + int ColorIndex; + int Count; +}; + +struct lcModelPartsEntry +{ + lcMatrix44 WorldMatrix; + PieceInfo* Info; + int ColorIndex; +}; + +class lcModel +{ +public: + lcModel(const QString& Name); + ~lcModel(); + + bool IsModified() const + { + return mSavedHistory != mUndoHistory[0]; + } + + bool IncludesModel(const lcModel* Model) const; + void CreatePieceInfo(Project* Project); + void UpdatePieceInfo(lcArray& UpdatedModels); + + PieceInfo* GetPieceInfo() const + { + return mPieceInfo; + } + + const lcArray& GetPieces() const + { + return mPieces; + } + + const lcArray& GetCameras() const + { + return mCameras; + } + + const lcArray& GetLights() const + { + return mLights; + } + + const lcArray& GetGroups() const + { + return mGroups; + } + + const lcModelProperties& GetProperties() const + { + return mProperties; + } + + void SetName(const QString& Name) + { + mProperties.mName = Name; + } + + const QStringList& GetFileLines() const + { + return mFileLines; + } + + lcStep GetLastStep() const; + + lcStep GetCurrentStep() const + { + return mCurrentStep; + } + + void SetActive(bool Active); + void CalculateStep(lcStep Step); + void SetCurrentStep(lcStep Step); + void SetTemporaryStep(lcStep Step) + { + mCurrentStep = Step; + CalculateStep(Step); + } + + void ShowFirstStep(); + void ShowLastStep(); + void ShowPreviousStep(); + void ShowNextStep(); + void InsertStep(lcStep Step); + void RemoveStep(lcStep Step); + + void AddPiece(); + void DeleteAllCameras(); + void DeleteSelectedObjects(); + void ResetSelectedPiecesPivotPoint(); + void InsertControlPoint(); + void RemoveFocusedControlPoint(); + void ShowSelectedPiecesEarlier(); + void ShowSelectedPiecesLater(); + void SetPieceSteps(const QList>& PieceSteps); + + void MoveSelectionToModel(lcModel* Model); + void InlineAllModels(); + void InlineSelectedModels(); + + lcGroup* AddGroup(const QString& Prefix, lcGroup* Parent); + lcGroup* GetGroup(const QString& Name, bool CreateIfMissing); + void RemoveGroup(lcGroup* Group); + void GroupSelection(); + void UngroupSelection(); + void AddSelectedPiecesToGroup(); + void RemoveFocusPieceFromGroup(); + void ShowEditGroupsDialog(); + + void SaveLDraw(QTextStream& Stream, bool SelectedOnly) const; + void LoadLDraw(QIODevice& Device, Project* Project); + bool LoadBinary(lcFile* File); + void Merge(lcModel* Other); + + void SetSaved() + { + if (mUndoHistory.IsEmpty()) + SaveCheckpoint(QString()); + + mSavedHistory = mUndoHistory[0]; + } + + void Cut(); + void Copy(); + void Paste(); + + void GetScene(lcScene& Scene, lcCamera* ViewCamera, bool DrawInterface) const; + void SubModelAddRenderMeshes(lcScene& Scene, const lcMatrix44& WorldMatrix, int DefaultColorIndex, bool Focused, bool Selected) const; + void DrawBackground(lcContext* Context); + void SaveStepImages(const QString& BaseName, int Width, int Height, lcStep Start, lcStep End); + + void RayTest(lcObjectRayTest& ObjectRayTest) const; + void BoxTest(lcObjectBoxTest& ObjectBoxTest) const; + bool SubModelMinIntersectDist(const lcVector3& WorldStart, const lcVector3& WorldEnd, float& MinDistance) const; + bool SubModelBoxTest(const lcVector4 Planes[6]) const; + + bool AnyPiecesSelected() const; + bool AnyObjectsSelected() const; + lcModel* GetFirstSelectedSubmodel() const; + void GetSubModels(lcArray SubModels) const; + bool GetMoveRotateTransform(lcVector3& Center, lcMatrix33& RelativeRotation) const; + bool GetPieceFocusOrSelectionCenter(lcVector3& Center) const; + lcVector3 GetSelectionOrModelCenter() const; + bool GetFocusPosition(lcVector3& Position) const; + lcObject* GetFocusObject() const; + bool GetSelectionCenter(lcVector3& Center) const; + bool GetPiecesBoundingBox(lcVector3& Min, lcVector3& Max) const; + void GetPartsList(int DefaultColorIndex, lcArray& PartsList) const; + void GetPartsListForStep(lcStep Step, int DefaultColorIndex, lcArray& PartsList) const; + void GetModelParts(const lcMatrix44& WorldMatrix, int DefaultColorIndex, lcArray& ModelParts) const; + void GetSelectionInformation(int* Flags, lcArray& Selection, lcObject** Focus) const; + + void FocusOrDeselectObject(const lcObjectSection& ObjectSection); + void ClearSelection(bool UpdateInterface); + void ClearSelectionAndSetFocus(lcObject* Object, lcuint32 Section); + void ClearSelectionAndSetFocus(const lcObjectSection& ObjectSection); + void SetSelectionAndFocus(const lcArray& Selection, lcObject* Focus, lcuint32 Section); + void AddToSelection(const lcArray& Objects); + void SelectAllPieces(); + void InvertSelection(); + + void HideSelectedPieces(); + void HideUnselectedPieces(); + void UnhideSelectedPieces(); + void UnhideAllPieces(); + + void FindPiece(bool FindFirst, bool SearchForward); + + void UndoAction(); + void RedoAction(); + + lcVector3 LockVector(const lcVector3& Vector) const; + lcVector3 SnapPosition(const lcVector3& Delta) const; + lcVector3 SnapRotation(const lcVector3& Delta) const; + lcMatrix33 GetRelativeRotation() const; + + const lcVector3& GetMouseToolDistance() const + { + return mMouseToolDistance; + } + + void BeginMouseTool(); + void EndMouseTool(lcTool Tool, bool Accept); + void InsertPieceToolClicked(const lcMatrix44& WorldMatrix); + void PointLightToolClicked(const lcVector3& Position); + void BeginSpotLightTool(const lcVector3& Position, const lcVector3& Target); + void UpdateSpotLightTool(const lcVector3& Position); + void BeginCameraTool(const lcVector3& Position, const lcVector3& Target); + void UpdateCameraTool(const lcVector3& Position); + void UpdateMoveTool(const lcVector3& Distance, bool AlternateButtonDrag); + void UpdateRotateTool(const lcVector3& Angles, bool AlternateButtonDrag); + void UpdateScaleTool(const float Scale); + void EraserToolClicked(lcObject* Object); + void PaintToolClicked(lcObject* Object); + void UpdateZoomTool(lcCamera* Camera, float Mouse); + void UpdatePanTool(lcCamera* Camera, const lcVector3& Distance); + void UpdateOrbitTool(lcCamera* Camera, float MouseX, float MouseY); + void UpdateRollTool(lcCamera* Camera, float Mouse); + void ZoomRegionToolClicked(lcCamera* Camera, float AspectRatio, const lcVector3& Position, const lcVector3& TargetPosition, const lcVector3* Corners); + void LookAt(lcCamera* Camera); + void ZoomExtents(lcCamera* Camera, float Aspect); + void Zoom(lcCamera* Camera, float Amount); + + void MoveSelectedObjects(const lcVector3& Distance, bool Relative, bool AlternateButtonDrag, bool Update, bool Checkpoint) + { + MoveSelectedObjects(Distance, Distance, Relative, AlternateButtonDrag, Update, Checkpoint); + } + + void MoveSelectedObjects(const lcVector3& PieceDistance, const lcVector3& ObjectDistance, bool Relative, bool AlternateButtonDrag, bool Update, bool Checkpoint); + void RotateSelectedPieces(const lcVector3& Angles, bool Relative, bool AlternateButtonDrag, bool Update, bool Checkpoint); + void ScaleSelectedPieces(const float Scale, bool Update, bool Checkpoint); + void TransformSelectedObjects(lcTransformType TransformType, const lcVector3& Transform); + void SetSelectedPiecesColorIndex(int ColorIndex); + void SetSelectedPiecesPieceInfo(PieceInfo* Info); + void SetSelectedPiecesStepShow(lcStep Step); + void SetSelectedPiecesStepHide(lcStep Step); + + void SetCameraOrthographic(lcCamera* Camera, bool Ortho); + void SetCameraFOV(lcCamera* Camera, float FOV); + void SetCameraZNear(lcCamera* Camera, float ZNear); + void SetCameraZFar(lcCamera* Camera, float ZFar); + void SetCameraName(lcCamera* Camera, const char* Name); + + void ShowPropertiesDialog(); + void ShowSelectByNameDialog(); + void ShowArrayDialog(); + void ShowMinifigDialog(); + void UpdateInterface(); + +protected: + void DeleteModel(); + void DeleteHistory(); + void SaveCheckpoint(const QString& Description); + void LoadCheckPoint(lcModelHistoryEntry* CheckPoint); + + QString GetGroupName(const QString& Prefix); + void RemoveEmptyGroups(); + bool RemoveSelectedObjects(); + + void UpdateBackgroundTexture(); + + void SelectGroup(lcGroup* TopGroup, bool Select); + + void AddPiece(lcPiece* Piece); + void InsertPiece(lcPiece* Piece, int Index); + + lcModelProperties mProperties; + PieceInfo* mPieceInfo; + + bool mActive; + lcStep mCurrentStep; + lcVector3 mMouseToolDistance; + lcTexture* mBackgroundTexture; + + lcArray mPieces; + lcArray mCameras; + lcArray mLights; + lcArray mGroups; + QStringList mFileLines; + + lcModelHistoryEntry* mSavedHistory; + lcArray mUndoHistory; + lcArray mRedoHistory; + + Q_DECLARE_TR_FUNCTIONS(lcModel); +}; + +#endif // _LC_MODEL_H_ diff --git a/common/lc_synth.cpp b/common/lc_synth.cpp index 2cf00bad..c71a5960 100644 --- a/common/lc_synth.cpp +++ b/common/lc_synth.cpp @@ -1,725 +1,725 @@ -#include "lc_global.h" -#include "lc_synth.h" -#include "lc_library.h" -#include "lc_application.h" -#include "lc_file.h" -#include "pieceinf.h" -#include - -void lcSynthInit() -{ - lcPiecesLibrary* Library = lcGetPiecesLibrary(); - - struct lcHoseInfo - { - const char* PartID; - lcSynthType Type; - float Length; - int NumSections; - }; - - lcHoseInfo HoseInfo[] = - { - { "72504", LC_SYNTH_PIECE_RIBBED_HOSE, 31.25f, 4 }, // Technic Ribbed Hose 2L - { "72706", LC_SYNTH_PIECE_RIBBED_HOSE, 50.00f, 7 }, // Technic Ribbed Hose 3L - { "71952", LC_SYNTH_PIECE_RIBBED_HOSE, 75.00f, 11 }, // Technic Ribbed Hose 4L - { "71944", LC_SYNTH_PIECE_RIBBED_HOSE, 112.50f, 17 }, // Technic Ribbed Hose 6L - { "71951", LC_SYNTH_PIECE_RIBBED_HOSE, 143.75f, 22 }, // Technic Ribbed Hose 8L - { "71986", LC_SYNTH_PIECE_RIBBED_HOSE, 212.50f, 33 }, // Technic Ribbed Hose 11L - { "43675", LC_SYNTH_PIECE_RIBBED_HOSE, 375.00f, 58 }, // Technic Ribbed Hose 19L - { "32580", LC_SYNTH_PIECE_FLEXIBLE_AXLE, 120.00f, 15 }, // Technic Axle Flexible 7 - { "32199", LC_SYNTH_PIECE_FLEXIBLE_AXLE, 200.00f, 35 }, // Technic Axle Flexible 11 - { "55709", LC_SYNTH_PIECE_FLEXIBLE_AXLE, 200.00f, 35 }, // Technic Axle Flexible 11 - { "32200", LC_SYNTH_PIECE_FLEXIBLE_AXLE, 220.00f, 40 }, // Technic Axle Flexible 12 - { "32201", LC_SYNTH_PIECE_FLEXIBLE_AXLE, 260.00f, 50 }, // Technic Axle Flexible 14 - { "32202", LC_SYNTH_PIECE_FLEXIBLE_AXLE, 300.00f, 60 }, // Technic Axle Flexible 16 - { "32235", LC_SYNTH_PIECE_FLEXIBLE_AXLE, 360.00f, 75 }, // Technic Axle Flexible 19 - { "76384", LC_SYNTH_PIECE_STRING_BRAIDED, 200.00f, 46 }, // String Braided 11L with End Studs - { "75924", LC_SYNTH_PIECE_STRING_BRAIDED, 400.00f, 96 }, // String Braided 21L with End Studs - { "572C02", LC_SYNTH_PIECE_STRING_BRAIDED, 800.00f, 196 }, // String Braided 41L with End Studs - { "73129", LC_SYNTH_PIECE_SHOCK_ABSORBER, 110.00f, 1 }, // Technic Shock Absorber 6.5L - { "41838", LC_SYNTH_PIECE_SHOCK_ABSORBER, 110.00f, 1 }, // Technic Shock Absorber 6.5L Soft - { "76138", LC_SYNTH_PIECE_SHOCK_ABSORBER, 110.00f, 1 }, // Technic Shock Absorber 6.5L Stiff - { "76537", LC_SYNTH_PIECE_SHOCK_ABSORBER, 110.00f, 1 } // Technic Shock Absorber 6.5L Extra Stiff - }; - - for (unsigned int InfoIdx = 0; InfoIdx < sizeof(HoseInfo) / sizeof(HoseInfo[0]); InfoIdx++) - { - PieceInfo* Info = Library->FindPiece(HoseInfo[InfoIdx].PartID, NULL, false); - - if (Info) - Info->SetSynthInfo(new lcSynthInfo(HoseInfo[InfoIdx].Type, HoseInfo[InfoIdx].Length, HoseInfo[InfoIdx].NumSections, Info)); - } - -// "758C01" // Hose Flexible 12L -// "73590A" // Hose Flexible 8.5L without Tabs -// "73590B" // Hose Flexible 8.5L with Tabs -} - -lcSynthInfo::lcSynthInfo(lcSynthType Type, float Length, int NumSections, PieceInfo* Info) - : mPieceInfo(Info), mType(Type), mLength(Length), mNumSections(NumSections) -{ - float EdgeSectionLength; - float MidSectionLength; - - switch (mType) - { - case LC_SYNTH_PIECE_RIBBED_HOSE: - EdgeSectionLength = 6.25f; - MidSectionLength = 6.25f; - mRigidEdges = false; - mCurve = true; - break; - - case LC_SYNTH_PIECE_FLEXIBLE_AXLE: - EdgeSectionLength = 30.0f; - MidSectionLength = 4.0f; - mRigidEdges = true; - mCurve = true; - break; - - case LC_SYNTH_PIECE_STRING_BRAIDED: - EdgeSectionLength = 8.0f; - MidSectionLength = 4.0f; - mRigidEdges = true; - mCurve = true; - break; - - case LC_SYNTH_PIECE_SHOCK_ABSORBER: - EdgeSectionLength = 0.0f; - MidSectionLength = 0.0f; - mRigidEdges = false; - mCurve = false; - break; - } - - if (mType != LC_SYNTH_PIECE_SHOCK_ABSORBER) - { - mStart.Transform = lcMatrix44(lcMatrix33(lcVector3(0.0f, 0.0f, 1.0f), lcVector3(1.0f, 0.0f, 0.0f), lcVector3(0.0f, 1.0f, 0.0f)), lcVector3(0.0f, 0.0f, 0.0f)); - mMiddle.Transform = lcMatrix44Identity(); - mEnd.Transform = lcMatrix44(lcMatrix33(lcVector3(0.0f, 0.0f, 1.0f), lcVector3(1.0f, 0.0f, 0.0f), lcVector3(0.0f, 1.0f, 0.0f)), lcVector3(0.0f, 0.0f, 0.0f)); - } - else - { - mStart.Transform = lcMatrix44Identity(); - mMiddle.Transform = lcMatrix44Identity(); - mEnd.Transform = lcMatrix44Identity(); - } - - mStart.Length = EdgeSectionLength; - mMiddle.Length = MidSectionLength; - mEnd.Length = EdgeSectionLength; -} - -void lcSynthInfo::GetDefaultControlPoints(lcArray& ControlPoints) const -{ - ControlPoints.SetSize(2); - - float Scale; - - switch (mType) - { - case LC_SYNTH_PIECE_RIBBED_HOSE: - Scale = 80.0f; - break; - - case LC_SYNTH_PIECE_FLEXIBLE_AXLE: - Scale = 12.0f; - break; - - case LC_SYNTH_PIECE_STRING_BRAIDED: - Scale = 12.0f; - break; - - case LC_SYNTH_PIECE_SHOCK_ABSORBER: - Scale = 1.0f; - break; - } - - float HalfLength = mLength / 2.0f; - Scale = lcMin(Scale, HalfLength); - - if (mType != LC_SYNTH_PIECE_SHOCK_ABSORBER) - { - ControlPoints[0].Transform = lcMatrix44Translation(lcVector3(-HalfLength, 0.0f, 0.0f)); - ControlPoints[1].Transform = lcMatrix44Translation(lcVector3( HalfLength, 0.0f, 0.0f)); - } - else - { - ControlPoints[0].Transform = lcMatrix44Translation(lcVector3(0.0f, 0.0f, -mLength)); - ControlPoints[1].Transform = lcMatrix44Translation(lcVector3(0.0f, 0.0f, 0.0f)); - } - - ControlPoints[0].Scale = Scale; - ControlPoints[1].Scale = Scale; -} - -float lcSynthInfo::GetSectionTwist(const lcMatrix44& StartTransform, const lcMatrix44& EndTransform) const -{ - lcVector3 StartTangent(StartTransform[1].x, StartTransform[1].y, StartTransform[1].z); - lcVector3 EndTangent(EndTransform[1].x, EndTransform[1].y, EndTransform[1].z); - lcVector3 StartUp(StartTransform[2].x, StartTransform[2].y, StartTransform[2].z); - lcVector3 EndUp(EndTransform[2].x, EndTransform[2].y, EndTransform[2].z); - - float TangentDot = lcDot(StartTangent, EndTangent); - float UpDot = lcDot(StartUp, EndUp); - - if (TangentDot > 0.99f && UpDot > 0.99f) - return 0.0f; - - if (fabs(TangentDot) > 0.99f) - { - return acosf(lcClamp(lcDot(EndUp, StartUp), -1.0f, 1.0f)); - } - else if (TangentDot > -0.99f) - { - lcVector3 Axis = lcCross(StartTangent, EndTangent); - float Angle = acosf(lcClamp(TangentDot, -1.0f, 1.0f)); - - lcMatrix33 Rotation = lcMatrix33FromAxisAngle(Axis, Angle); - lcVector3 AdjustedStartUp = lcMul(StartUp, Rotation); - return acosf(lcClamp(lcDot(EndUp, AdjustedStartUp), -1.0f, 1.0f)); - } - - lcVector3 StartSide(StartTransform[0].x, StartTransform[0].y, StartTransform[0].z); - lcVector3 EndSide(EndTransform[0].x, EndTransform[0].y, EndTransform[0].z); - - float SideDot = lcDot(StartSide, EndSide); - - if (fabs(SideDot) < 0.99f) - { - lcVector3 Axis = lcCross(StartSide, EndSide); - float Angle = acosf(SideDot); - - lcMatrix33 Rotation = lcMatrix33FromAxisAngle(Axis, Angle); - lcVector3 AdjustedStartUp = lcMul(StartUp, Rotation); - return acosf(lcClamp(lcDot(EndUp, AdjustedStartUp), -1.0f, 1.0f)); - } - - return 0.0f; -} - -void lcSynthInfo::CalculateCurveSections(const lcArray& ControlPoints, lcArray& Sections, void (*SectionCallback)(const lcVector3& CurvePoint, int SegmentIndex, float t, void* Param), void* CallbackParam) const -{ - float SectionLength = 0.0f; - - for (int ControlPointIdx = 0; ControlPointIdx < ControlPoints.GetSize() - 1 && Sections.GetSize() < mNumSections + 2; ControlPointIdx++) - { - lcVector3 SegmentControlPoints[4]; - - lcMatrix44 StartTransform = lcMatrix44LeoCADToLDraw(ControlPoints[ControlPointIdx].Transform); - lcMatrix44 EndTransform = lcMatrix44LeoCADToLDraw(ControlPoints[ControlPointIdx + 1].Transform); - StartTransform = lcMatrix44(lcMul(lcMul(lcMatrix33(mStart.Transform), lcMatrix33(StartTransform)), lcMatrix33Scale(lcVector3(1.0f, -1.0f, 1.0f))), StartTransform.GetTranslation()); - - if (ControlPointIdx == 0) - { - if (mRigidEdges) - { - StartTransform.SetTranslation(lcMul30(lcVector3(0.0f, mStart.Length, 0.0f), StartTransform) + StartTransform.GetTranslation()); - SectionLength = 0.0f; - } - else - SectionLength = mStart.Length; - - Sections.Add(StartTransform); - } - - EndTransform = lcMatrix44(lcMul(lcMul(lcMatrix33(mEnd.Transform), lcMatrix33(EndTransform)), lcMatrix33Scale(lcVector3(1.0f, -1.0f, 1.0f))), EndTransform.GetTranslation()); - - SegmentControlPoints[0] = StartTransform.GetTranslation(); - SegmentControlPoints[1] = lcMul31(lcVector3(0.0f, ControlPoints[ControlPointIdx].Scale, 0.0f), StartTransform); - SegmentControlPoints[2] = lcMul31(lcVector3(0.0f, -ControlPoints[ControlPointIdx + 1].Scale, 0.0f), EndTransform); - SegmentControlPoints[3] = EndTransform.GetTranslation(); - - const int NumCurvePoints = 8192; - lcArray CurvePoints; - CurvePoints.AllocGrow(NumCurvePoints); - - for (int PointIdx = 0; PointIdx < NumCurvePoints; PointIdx++) - { - float t = (float)PointIdx / (float)(NumCurvePoints - 1); - float it = 1.0f - t; - - lcVector3 Position = it * it * it * SegmentControlPoints[0] + it * it * 3.0f * t * SegmentControlPoints[1] + it * 3.0 * t * t * SegmentControlPoints[2] + t * t * t * SegmentControlPoints[3]; - CurvePoints.Add(Position); - } - - float CurrentSegmentLength = 0.0f; - float TotalSegmentLength = 0.0f; - - for (int PointIdx = 0; PointIdx < CurvePoints.GetSize() - 1; PointIdx++) - TotalSegmentLength += lcLength(CurvePoints[PointIdx] - CurvePoints[PointIdx + 1]); - - lcVector3 StartUp(lcMul30(lcVector3(1.0f, 0.0f, 0.0f), StartTransform)); - float Twist = GetSectionTwist(StartTransform, EndTransform); - int CurrentPointIndex = 0; - - while (CurrentPointIndex < CurvePoints.GetSize() - 1) - { - float Length = lcLength(CurvePoints[CurrentPointIndex + 1] - CurvePoints[CurrentPointIndex]); - CurrentSegmentLength += Length; - SectionLength -= Length; - CurrentPointIndex++; - - if (SectionLength > 0.0f) - continue; - - float t = (float)CurrentPointIndex / (float)(NumCurvePoints - 1); - float it = 1.0f - t; - - lcVector3 Tangent = lcNormalize(-3.0f * it * it * SegmentControlPoints[0] + (3.0f * it * it - 6.0f * t * it) * SegmentControlPoints[1] + (-3.0f * t * t + 6.0f * t * it) * SegmentControlPoints[2] + 3.0f * t * t * SegmentControlPoints[3]); - lcVector3 Up; - - if (Twist) - { - Up = lcMul(StartUp, lcMatrix33FromAxisAngle(Tangent, Twist * (CurrentSegmentLength / TotalSegmentLength))); - CurrentSegmentLength = 0.0f; - } - else - Up = StartUp; - - lcVector3 Side = lcNormalize(lcCross(Tangent, Up)); - Up = lcNormalize(lcCross(Side, Tangent)); - StartUp = Up; - - Sections.Add(lcMatrix44(lcMatrix33(Up, Tangent, Side), CurvePoints[CurrentPointIndex])); - - if (SectionCallback) - SectionCallback(CurvePoints[CurrentPointIndex], ControlPointIdx, t, CallbackParam); - - if (Sections.GetSize() == mNumSections + 2) - break; - - SectionLength += mMiddle.Length; - if (Sections.GetSize() == mNumSections + 1 && !mRigidEdges) - SectionLength += mEnd.Length; - } - } - - while (Sections.GetSize() < mNumSections + 2) - { - lcMatrix44 EndTransform = lcMatrix44LeoCADToLDraw(ControlPoints[ControlPoints.GetSize() - 1].Transform); - EndTransform = lcMatrix44(lcMul(lcMul(lcMatrix33(mEnd.Transform), lcMatrix33(EndTransform)), lcMatrix33Scale(lcVector3(1.0f, -1.0f, 1.0f))), EndTransform.GetTranslation()); - lcVector3 Position = lcMul31(lcVector3(0.0f, SectionLength, 0.0f), EndTransform); - EndTransform.SetTranslation(Position); - Sections.Add(EndTransform); - - if (SectionCallback) - SectionCallback(Position, ControlPoints.GetSize() - 1, 1.0f, CallbackParam); - - SectionLength += mMiddle.Length; - if (Sections.GetSize() == mNumSections + 1 && !mRigidEdges) - SectionLength += mEnd.Length; - } -} - -void lcSynthInfo::CalculateLineSections(const lcArray& ControlPoints, lcArray& Sections, void(*SectionCallback)(const lcVector3& CurvePoint, int SegmentIndex, float t, void* Param), void* CallbackParam) const -{ - for (int ControlPointIdx = 0; ControlPointIdx < ControlPoints.GetSize(); ControlPointIdx++) - { - lcMatrix44 Transform = lcMatrix44LeoCADToLDraw(ControlPoints[ControlPointIdx].Transform); - Sections.Add(Transform); - - if (SectionCallback) - SectionCallback(Transform.GetTranslation(), ControlPointIdx, 1.0f, CallbackParam); - } -} - -void lcSynthInfo::AddRibbedHoseParts(lcMemFile& File, const lcArray& Sections) const -{ - char Line[256]; - - { - const int SectionIdx = 0; - lcMatrix33 Transform(lcMul(lcMatrix33Scale(lcVector3(1.0f, -1.0f, 1.0f)), lcMatrix33(Sections[SectionIdx]))); - lcVector3 Offset = Sections[SectionIdx].GetTranslation(); - - sprintf(Line, "1 16 %f %f %f %f %f %f %f %f %f %f %f %f 79.DAT\n", Offset[0], Offset[1], Offset[2], Transform[0][0], Transform[1][0], Transform[2][0], - Transform[0][1], Transform[1][1], Transform[2][1], Transform[0][2], Transform[1][2], Transform[2][2]); - - File.WriteBuffer(Line, strlen(Line)); - } - - for (int SectionIdx = 1; SectionIdx < Sections.GetSize() - 1; SectionIdx++) - { - const lcMatrix44& Transform = Sections[SectionIdx]; - - sprintf(Line, "1 16 %f %f %f %f %f %f %f %f %f %f %f %f 80.DAT\n", Transform[3][0], Transform[3][1], Transform[3][2], Transform[0][0], Transform[1][0], Transform[2][0], - Transform[0][1], Transform[1][1], Transform[2][1], Transform[0][2], Transform[1][2], Transform[2][2]); - - File.WriteBuffer(Line, strlen(Line)); - } - - { - const int SectionIdx = Sections.GetSize() - 1; - lcMatrix33 Transform(Sections[SectionIdx]); - lcVector3 Offset = lcMul31(lcVector3(0.0f, -6.25f, 0.0f), Sections[SectionIdx]); - - sprintf(Line, "1 16 %f %f %f %f %f %f %f %f %f %f %f %f 79.DAT\n", Offset[0], Offset[1], Offset[2], Transform[0][0], Transform[1][0], Transform[2][0], - Transform[0][1], Transform[1][1], Transform[2][1], Transform[0][2], Transform[1][2], Transform[2][2]); - - File.WriteBuffer(Line, strlen(Line)); - } -} - -void lcSynthInfo::AddFlexibleAxleParts(lcMemFile& File, lcLibraryMeshData& MeshData, const lcArray& Sections) const -{ - char Line[256]; - const int NumEdgeParts = 6; - - lcMatrix33 EdgeTransforms[6] = - { - lcMatrix33(lcVector3(-1.0f, 0.0f, 0.0f), lcVector3(0.0f, -5.0f, 0.0f), lcVector3(0.0f, 0.0f, 1.0f)), - lcMatrix33(lcVector3( 0.0f, 1.0f, 0.0f), lcVector3(1.0f, 0.0f, 0.0f), lcVector3(0.0f, 0.0f, -1.0f)), - lcMatrix33(lcVector3( 0.0f, 1.0f, 0.0f), lcVector3(1.0f, 0.0f, 0.0f), lcVector3(0.0f, 0.0f, -1.0f)), - lcMatrix33(lcVector3( 0.0f, 1.0f, 0.0f), lcVector3(1.0f, 0.0f, 0.0f), lcVector3(0.0f, 0.0f, -1.0f)), - lcMatrix33(lcVector3( 0.0f, 1.0f, 0.0f), lcVector3(1.0f, 0.0f, 0.0f), lcVector3(0.0f, 0.0f, -1.0f)), - lcMatrix33(lcVector3( 0.0f, 1.0f, 0.0f), lcVector3(1.0f, 0.0f, 0.0f), lcVector3(0.0f, 0.0f, -1.0f)), - }; - - const char* EdgeParts[6] = - { - "STUD3A.DAT", "S/FAXLE1.DAT", "S/FAXLE2.DAT", "S/FAXLE3.DAT", "S/FAXLE4.DAT", "S/FAXLE5.DAT" - }; - - for (int PartIdx = 0; PartIdx < NumEdgeParts; PartIdx++) - { - const int SectionIdx = 0; - lcMatrix33 Transform(lcMul(lcMul(EdgeTransforms[PartIdx], lcMatrix33Scale(lcVector3(1.0f, -1.0f, 1.0f))), lcMatrix33(Sections[SectionIdx]))); - lcVector3 Offset = lcMul31(lcVector3(0.0f, -4.0f * (5 - PartIdx), 0.0f), Sections[SectionIdx]); - - sprintf(Line, "1 16 %f %f %f %f %f %f %f %f %f %f %f %f %s\n", Offset[0], Offset[1], Offset[2], Transform[0][0], Transform[1][0], Transform[2][0], - Transform[0][1], Transform[1][1], Transform[2][1], Transform[0][2], Transform[1][2], Transform[2][2], EdgeParts[PartIdx]); - - File.WriteBuffer(Line, strlen(Line)); - } - - for (int PartIdx = 0; PartIdx < NumEdgeParts; PartIdx++) - { - const int SectionIdx = Sections.GetSize() - 1; - lcMatrix33 Transform(lcMul(EdgeTransforms[PartIdx], lcMatrix33(Sections[SectionIdx]))); - lcVector3 Offset = lcMul31(lcVector3(0.0f, 4.0f * (5 - PartIdx), 0.0f), Sections[SectionIdx]); - - sprintf(Line, "1 16 %f %f %f %f %f %f %f %f %f %f %f %f %s\n", Offset[0], Offset[1], Offset[2], Transform[0][0], Transform[1][0], Transform[2][0], - Transform[0][1], Transform[1][1], Transform[2][1], Transform[0][2], Transform[1][2], Transform[2][2], EdgeParts[PartIdx]); - - File.WriteBuffer(Line, strlen(Line)); - } - - lcVector3 SectionVertices[16] = - { - lcVector3(-6.000f, 0.0f, 0.000f), lcVector3(-5.602f, 0.0f, 2.000f), lcVector3(-2.000f, 0.0f, 2.000f), lcVector3(-2.000f, 0.0f, 5.602f), - lcVector3( 0.000f, 0.0f, 6.000f), lcVector3( 2.000f, 0.0f, 5.602f), lcVector3( 2.000f, 0.0f, 2.000f), lcVector3( 5.602f, 0.0f, 2.000f), - lcVector3( 6.000f, 0.0f, 0.000f), lcVector3( 5.602f, 0.0f, -2.000f), lcVector3( 2.000f, 0.0f, -2.000f), lcVector3( 2.000f, 0.0f, -5.602f), - lcVector3( 0.000f, 0.0f, -6.000f), lcVector3(-2.000f, 0.0f, -5.602f), lcVector3(-2.000f, 0.0f, -2.000f), lcVector3(-5.602f, 0.0f, -2.000f) - }; - - int BaseVertex; - lcVertex* VertexBuffer; - lcuint32* IndexBuffer; - MeshData.AddVertices(LC_MESHDATA_SHARED, 16 * (Sections.GetSize() - 1), &BaseVertex, &VertexBuffer); - MeshData.AddIndices(LC_MESHDATA_SHARED, LC_MESH_LINES, 24, 2 * 12 * (Sections.GetSize() - 2), &IndexBuffer); - - for (int SectionIdx = 1; SectionIdx < Sections.GetSize(); SectionIdx++) - { - for (int VertexIdx = 0; VertexIdx < 16; VertexIdx++) - { - VertexBuffer->Position = lcMul31(SectionVertices[VertexIdx], Sections[SectionIdx]); - VertexBuffer++; - } - } - - int BaseLinesVertex = BaseVertex; - - for (int SectionIdx = 1; SectionIdx < Sections.GetSize() - 1; SectionIdx++) - { - for (int VertexIdx = 0; VertexIdx < 16; VertexIdx++) - { - if (VertexIdx % 4) - { - *IndexBuffer++ = BaseLinesVertex; - *IndexBuffer++ = BaseLinesVertex + 16; - } - BaseLinesVertex++; - } - } - - MeshData.AddIndices(LC_MESHDATA_SHARED, LC_MESH_TRIANGLES, 16, 6 * 16 * (Sections.GetSize() - 2), &IndexBuffer); - - for (int SectionIdx = 1; SectionIdx < Sections.GetSize() - 1; SectionIdx++) - { - for (int VertexIdx = 0; VertexIdx < 16; VertexIdx++) - { - int Vertex1 = BaseVertex + VertexIdx; - int Vertex2 = BaseVertex + (VertexIdx + 1) % 16; - - *IndexBuffer++ = Vertex1; - *IndexBuffer++ = Vertex2; - *IndexBuffer++ = Vertex1 + 16; - *IndexBuffer++ = Vertex2; - *IndexBuffer++ = Vertex2 + 16; - *IndexBuffer++ = Vertex1 + 16; - } - BaseVertex += 16; - } -} - -void lcSynthInfo::AddStringBraidedParts(lcMemFile& File, lcLibraryMeshData& MeshData, lcArray& Sections) const -{ - for (int SectionIdx = 0; SectionIdx < Sections.GetSize(); SectionIdx++) - { - lcMatrix33 Transform = lcMul(lcMatrix33(lcVector3(0.0f, 1.0f, 0.0f), lcVector3(1.0f, 0.0f, 0.0f), lcVector3(0.0f, 0.0f, 1.0f)), lcMatrix33(Sections[SectionIdx])); - lcVector3 Offset = Sections[SectionIdx].GetTranslation(); - Sections[SectionIdx] = lcMatrix44(Transform, Offset); - } - - char Line[256]; - - { - const int SectionIdx = 0; - lcMatrix33 Transform(Sections[SectionIdx]); - lcVector3 Offset = lcMul31(lcVector3(-8.0f, 0.0f, 0.0f), Sections[SectionIdx]); - - sprintf(Line, "1 16 %f %f %f %f %f %f %f %f %f %f %f %f 572A.DAT\n", Offset[0], Offset[1], Offset[2], Transform[0][0], Transform[1][0], Transform[2][0], - Transform[0][1], Transform[1][1], Transform[2][1], Transform[0][2], Transform[1][2], Transform[2][2]); - - File.WriteBuffer(Line, strlen(Line)); - } - - const int NumSegments = 16; - const int NumBraids = 4; - const float PositionTable[16] = - { - -1.5f, -1.386f, -1.061f, -0.574f, 0.0f, 0.574f, 1.061f, 1.386f, 1.5f, 1.386f, 1.061f, 0.574f, 0.0f, -0.574f, -1.061f, -1.386f - }; - - int BaseVertex; - lcVertex* VertexBuffer; - lcuint32* IndexBuffer; - MeshData.AddVertices(LC_MESHDATA_SHARED, NumBraids * ((Sections.GetSize() - 2) * NumSegments + 1), &BaseVertex, &VertexBuffer); - MeshData.AddIndices(LC_MESHDATA_SHARED, LC_MESH_LINES, 24, NumBraids * (Sections.GetSize() - 2) * NumSegments * 2, &IndexBuffer); - - for (int BraidIdx = 0; BraidIdx < NumBraids; BraidIdx++) - { - int BaseX = (BraidIdx == 0 || BraidIdx == 2) ? 0 : 8; - int BaseY = (BraidIdx == 0 || BraidIdx == 3) ? 12 : 4; - - for (int SectionIdx = 1; SectionIdx < Sections.GetSize() - 1; SectionIdx++) - { - lcMatrix33 Transform1 = lcMatrix33(Sections[SectionIdx]); - lcMatrix33 Transform2 = lcMatrix33(Sections[SectionIdx + 1]); - lcVector3 Offset1 = Sections[SectionIdx].GetTranslation(); - lcVector3 Offset2 = Sections[SectionIdx + 1].GetTranslation(); - - for (int SegmentIdx = 0; SegmentIdx < ((SectionIdx < Sections.GetSize() - 2) ? NumSegments : NumSegments + 1); SegmentIdx++) - { - float t = (float)SegmentIdx / (float)NumSegments; - - lcVector3 Vertex1 = lcVector3(t * 4.0f, PositionTable[(BaseX + SegmentIdx) % NumSegments], PositionTable[(BaseY + SegmentIdx) % NumSegments]) + lcVector3(0.0f, 1.5f, 0.0f); - lcVector3 Vertex2 = lcVector3((1.0f - t) * -4.0f, PositionTable[(BaseX + SegmentIdx) % NumSegments], PositionTable[(BaseY + SegmentIdx) % NumSegments]) + lcVector3(0.0f, 1.5f, 0.0f); - - lcVector3 Vertex = (lcMul(Vertex1, Transform1) + Offset1) * (1.0f - t) + (lcMul(Vertex2, Transform2) + Offset2) * t; - - VertexBuffer->Position = Vertex; - VertexBuffer++; - - if (SegmentIdx != NumSegments) - { - *IndexBuffer++ = BaseVertex; - *IndexBuffer++ = BaseVertex + 1; - BaseVertex++; - } - } - } - - BaseVertex++; - } - - int NumSlices = 16; - MeshData.AddVertices(LC_MESHDATA_SHARED, NumSlices * ((Sections.GetSize() - 2) * NumSegments + 1), &BaseVertex, &VertexBuffer); - MeshData.AddIndices(LC_MESHDATA_SHARED, LC_MESH_TRIANGLES, 16, NumSlices * (Sections.GetSize() - 2) * NumSegments * 6, &IndexBuffer); - - for (int SectionIdx = 1; SectionIdx < Sections.GetSize() - 1; SectionIdx++) - { - lcMatrix33 Transform1 = lcMatrix33(Sections[SectionIdx]); - lcMatrix33 Transform2 = lcMatrix33(Sections[SectionIdx + 1]); - lcVector3 Offset1 = Sections[SectionIdx].GetTranslation(); - lcVector3 Offset2 = Sections[SectionIdx + 1].GetTranslation(); - - for (int SegmentIdx = 0; SegmentIdx < ((SectionIdx < Sections.GetSize() - 2) ? NumSegments : NumSegments + 1); SegmentIdx++) - { - float t1 = (float)SegmentIdx / (float)NumSegments; - int BaseX = 8; - int BaseY = 4; - - for (int SliceIdx = 0; SliceIdx < NumSlices; SliceIdx++) - { - lcVector3 Vertex11 = lcVector3(t1 * 4.0f, PositionTable[(BaseX + SliceIdx) % NumSlices], PositionTable[(BaseY + SliceIdx) % NumSlices]) + lcVector3(0.0f, 1.5f, 0.0f); - lcVector3 Vertex12 = lcVector3((1.0f - t1) * -4.0f, PositionTable[(BaseX + SliceIdx) % NumSlices], PositionTable[(BaseY + SliceIdx) % NumSlices]) + lcVector3(0.0f, 1.5f, 0.0f); - - lcVector3 Vertex1 = (lcMul(Vertex11, Transform1) + Offset1) * (1.0f - t1) + (lcMul(Vertex12, Transform2) + Offset2) * t1; - - VertexBuffer->Position = Vertex1; - VertexBuffer++; - - if (SegmentIdx != NumSegments) - { - *IndexBuffer++ = BaseVertex + SliceIdx; - *IndexBuffer++ = BaseVertex + (SliceIdx + 1) % NumSlices; - *IndexBuffer++ = BaseVertex + (SliceIdx + 1) % NumSlices + NumSlices; - - *IndexBuffer++ = BaseVertex + SliceIdx + NumSlices; - *IndexBuffer++ = BaseVertex + SliceIdx; - *IndexBuffer++ = BaseVertex + (SliceIdx + 1) % NumSlices + NumSlices; - } - } - - BaseVertex += NumSlices; - } - } - - { - const int SectionIdx = Sections.GetSize() - 1; - lcMatrix33 Transform(Sections[SectionIdx]); - lcVector3 Offset = lcMul31(lcVector3(8.0f, 0.0f, 0.0f), Sections[SectionIdx]); - - sprintf(Line, "1 16 %f %f %f %f %f %f %f %f %f %f %f %f 572A.DAT\n", Offset[0], Offset[1], Offset[2], Transform[0][0], Transform[1][0], Transform[2][0], - Transform[0][1], Transform[1][1], Transform[2][1], Transform[0][2], Transform[1][2], Transform[2][2]); - - File.WriteBuffer(Line, strlen(Line)); - } -} - -void lcSynthInfo::AddShockAbsorberParts(lcMemFile& File, lcArray& Sections) const -{ - char Line[256]; - lcVector3 Offset; - - Offset = Sections[0].GetTranslation(); - sprintf(Line, "1 0 %f %f %f 1 0 0 0 1 0 0 0 1 4254.DAT\n", Offset[0], Offset[1], Offset[2]); - File.WriteBuffer(Line, strlen(Line)); - - Offset = Sections[1].GetTranslation(); - sprintf(Line, "1 16 %f %f %f 1 0 0 0 1 0 0 0 1 4255.DAT\n", Offset[0], Offset[1], Offset[2]); - File.WriteBuffer(Line, strlen(Line)); - - float Distance = Sections[0].GetTranslation().y - Sections[1].GetTranslation().y; - float Scale = (Distance - 66.0f) / 44.0f; - const char* SpringPart; - - if (!strcmp(mPieceInfo->m_strName, "73129")) - SpringPart = "70038"; - else if (!strcmp(mPieceInfo->m_strName, "41838")) - SpringPart = "41837"; - else if (!strcmp(mPieceInfo->m_strName, "76138")) - SpringPart = "71953"; - else if (!strcmp(mPieceInfo->m_strName, "76537")) - SpringPart = "22977"; - else - return; - - Offset = Sections[0].GetTranslation(); - sprintf(Line, "1 494 %f %f %f 1 0 0 0 %f 0 0 0 1 %s.DAT\n", Offset[0], Offset[1] - 10 - 44.0f * Scale, Offset[2], Scale, SpringPart); - File.WriteBuffer(Line, strlen(Line)); -} - -lcMesh* lcSynthInfo::CreateMesh(const lcArray& ControlPoints) const -{ - lcArray Sections; - - if (mCurve) - CalculateCurveSections(ControlPoints, Sections, NULL, NULL); - else - CalculateLineSections(ControlPoints, Sections, NULL, NULL); - - lcLibraryMeshData MeshData; - lcMemFile File; // todo: rewrite this to pass the parts directly - const char* OldLocale = setlocale(LC_NUMERIC, "C"); - - switch (mType) - { - case LC_SYNTH_PIECE_RIBBED_HOSE: - AddRibbedHoseParts(File, Sections); - break; - - case LC_SYNTH_PIECE_FLEXIBLE_AXLE: - AddFlexibleAxleParts(File, MeshData, Sections); - break; - - case LC_SYNTH_PIECE_STRING_BRAIDED: - AddStringBraidedParts(File, MeshData, Sections); - break; - - case LC_SYNTH_PIECE_SHOCK_ABSORBER: - AddShockAbsorberParts(File, Sections); - break; - } - - File.WriteU8(0); - - lcArray TextureStack; - File.Seek(0, SEEK_SET); - - bool Ret = lcGetPiecesLibrary()->ReadMeshData(File, lcMatrix44Identity(), 16, TextureStack, MeshData, LC_MESHDATA_SHARED, false); - setlocale(LC_NUMERIC, OldLocale); - - if (Ret) - return lcGetPiecesLibrary()->CreateMesh(NULL, MeshData); - - return NULL; -} - -struct lcSynthInsertParam -{ - lcVector3 Start; - lcVector3 End; - int BestSegment; - float BestTime; - float BestDistance; - lcVector3 BestPosition; -}; - -static void lcSynthInsertCallback(const lcVector3& CurvePoint, int SegmentIndex, float t, void* Param) -{ - lcSynthInsertParam* SynthInsertParam = (lcSynthInsertParam*)Param; - - float Distance = lcRayPointDistance(CurvePoint, SynthInsertParam->Start, SynthInsertParam->End); - if (Distance < SynthInsertParam->BestDistance) - { - SynthInsertParam->BestSegment = SegmentIndex; - SynthInsertParam->BestTime = t; - SynthInsertParam->BestDistance = Distance; - SynthInsertParam->BestPosition = lcVector3LDrawToLeoCAD(CurvePoint); - } -} - -int lcSynthInfo::InsertControlPoint(lcArray& ControlPoints, const lcVector3& Start, const lcVector3& End) const -{ - lcArray Sections; - lcSynthInsertParam SynthInsertParam; - - SynthInsertParam.Start = Start; - SynthInsertParam.End = End; - SynthInsertParam.BestSegment = -1; - SynthInsertParam.BestDistance = FLT_MAX; - - CalculateCurveSections(ControlPoints, Sections, lcSynthInsertCallback, &SynthInsertParam); - - if (SynthInsertParam.BestSegment != -1) - { - lcPieceControlPoint ControlPoint = ControlPoints[SynthInsertParam.BestSegment]; - ControlPoint.Transform.SetTranslation(SynthInsertParam.BestPosition); - - if (SynthInsertParam.BestSegment != ControlPoints.GetSize() - 1) - { - lcPieceControlPoint NextControlPoint = ControlPoints[SynthInsertParam.BestSegment + 1]; - float t = SynthInsertParam.BestTime; - - ControlPoint.Scale = ControlPoint.Scale * (1.0f - t) + NextControlPoint.Scale * t; - } - - ControlPoints.InsertAt(SynthInsertParam.BestSegment + 1, ControlPoint); - } - - return SynthInsertParam.BestSegment + 1; -} +#include "lc_global.h" +#include "lc_synth.h" +#include "lc_library.h" +#include "lc_application.h" +#include "lc_file.h" +#include "pieceinf.h" +#include + +void lcSynthInit() +{ + lcPiecesLibrary* Library = lcGetPiecesLibrary(); + + struct lcHoseInfo + { + const char* PartID; + lcSynthType Type; + float Length; + int NumSections; + }; + + lcHoseInfo HoseInfo[] = + { + { "72504", LC_SYNTH_PIECE_RIBBED_HOSE, 31.25f, 4 }, // Technic Ribbed Hose 2L + { "72706", LC_SYNTH_PIECE_RIBBED_HOSE, 50.00f, 7 }, // Technic Ribbed Hose 3L + { "71952", LC_SYNTH_PIECE_RIBBED_HOSE, 75.00f, 11 }, // Technic Ribbed Hose 4L + { "71944", LC_SYNTH_PIECE_RIBBED_HOSE, 112.50f, 17 }, // Technic Ribbed Hose 6L + { "71951", LC_SYNTH_PIECE_RIBBED_HOSE, 143.75f, 22 }, // Technic Ribbed Hose 8L + { "71986", LC_SYNTH_PIECE_RIBBED_HOSE, 212.50f, 33 }, // Technic Ribbed Hose 11L + { "43675", LC_SYNTH_PIECE_RIBBED_HOSE, 375.00f, 58 }, // Technic Ribbed Hose 19L + { "32580", LC_SYNTH_PIECE_FLEXIBLE_AXLE, 120.00f, 15 }, // Technic Axle Flexible 7 + { "32199", LC_SYNTH_PIECE_FLEXIBLE_AXLE, 200.00f, 35 }, // Technic Axle Flexible 11 + { "55709", LC_SYNTH_PIECE_FLEXIBLE_AXLE, 200.00f, 35 }, // Technic Axle Flexible 11 + { "32200", LC_SYNTH_PIECE_FLEXIBLE_AXLE, 220.00f, 40 }, // Technic Axle Flexible 12 + { "32201", LC_SYNTH_PIECE_FLEXIBLE_AXLE, 260.00f, 50 }, // Technic Axle Flexible 14 + { "32202", LC_SYNTH_PIECE_FLEXIBLE_AXLE, 300.00f, 60 }, // Technic Axle Flexible 16 + { "32235", LC_SYNTH_PIECE_FLEXIBLE_AXLE, 360.00f, 75 }, // Technic Axle Flexible 19 + { "76384", LC_SYNTH_PIECE_STRING_BRAIDED, 200.00f, 46 }, // String Braided 11L with End Studs + { "75924", LC_SYNTH_PIECE_STRING_BRAIDED, 400.00f, 96 }, // String Braided 21L with End Studs + { "572C02", LC_SYNTH_PIECE_STRING_BRAIDED, 800.00f, 196 }, // String Braided 41L with End Studs + { "73129", LC_SYNTH_PIECE_SHOCK_ABSORBER, 110.00f, 1 }, // Technic Shock Absorber 6.5L + { "41838", LC_SYNTH_PIECE_SHOCK_ABSORBER, 110.00f, 1 }, // Technic Shock Absorber 6.5L Soft + { "76138", LC_SYNTH_PIECE_SHOCK_ABSORBER, 110.00f, 1 }, // Technic Shock Absorber 6.5L Stiff + { "76537", LC_SYNTH_PIECE_SHOCK_ABSORBER, 110.00f, 1 } // Technic Shock Absorber 6.5L Extra Stiff + }; + + for (unsigned int InfoIdx = 0; InfoIdx < sizeof(HoseInfo) / sizeof(HoseInfo[0]); InfoIdx++) + { + PieceInfo* Info = Library->FindPiece(HoseInfo[InfoIdx].PartID, NULL, false); + + if (Info) + Info->SetSynthInfo(new lcSynthInfo(HoseInfo[InfoIdx].Type, HoseInfo[InfoIdx].Length, HoseInfo[InfoIdx].NumSections, Info)); + } + +// "758C01" // Hose Flexible 12L +// "73590A" // Hose Flexible 8.5L without Tabs +// "73590B" // Hose Flexible 8.5L with Tabs +} + +lcSynthInfo::lcSynthInfo(lcSynthType Type, float Length, int NumSections, PieceInfo* Info) + : mPieceInfo(Info), mType(Type), mLength(Length), mNumSections(NumSections) +{ + float EdgeSectionLength; + float MidSectionLength; + + switch (mType) + { + case LC_SYNTH_PIECE_RIBBED_HOSE: + EdgeSectionLength = 6.25f; + MidSectionLength = 6.25f; + mRigidEdges = false; + mCurve = true; + break; + + case LC_SYNTH_PIECE_FLEXIBLE_AXLE: + EdgeSectionLength = 30.0f; + MidSectionLength = 4.0f; + mRigidEdges = true; + mCurve = true; + break; + + case LC_SYNTH_PIECE_STRING_BRAIDED: + EdgeSectionLength = 8.0f; + MidSectionLength = 4.0f; + mRigidEdges = true; + mCurve = true; + break; + + case LC_SYNTH_PIECE_SHOCK_ABSORBER: + EdgeSectionLength = 0.0f; + MidSectionLength = 0.0f; + mRigidEdges = false; + mCurve = false; + break; + } + + if (mType != LC_SYNTH_PIECE_SHOCK_ABSORBER) + { + mStart.Transform = lcMatrix44(lcMatrix33(lcVector3(0.0f, 0.0f, 1.0f), lcVector3(1.0f, 0.0f, 0.0f), lcVector3(0.0f, 1.0f, 0.0f)), lcVector3(0.0f, 0.0f, 0.0f)); + mMiddle.Transform = lcMatrix44Identity(); + mEnd.Transform = lcMatrix44(lcMatrix33(lcVector3(0.0f, 0.0f, 1.0f), lcVector3(1.0f, 0.0f, 0.0f), lcVector3(0.0f, 1.0f, 0.0f)), lcVector3(0.0f, 0.0f, 0.0f)); + } + else + { + mStart.Transform = lcMatrix44Identity(); + mMiddle.Transform = lcMatrix44Identity(); + mEnd.Transform = lcMatrix44Identity(); + } + + mStart.Length = EdgeSectionLength; + mMiddle.Length = MidSectionLength; + mEnd.Length = EdgeSectionLength; +} + +void lcSynthInfo::GetDefaultControlPoints(lcArray& ControlPoints) const +{ + ControlPoints.SetSize(2); + + float Scale; + + switch (mType) + { + case LC_SYNTH_PIECE_RIBBED_HOSE: + Scale = 80.0f; + break; + + case LC_SYNTH_PIECE_FLEXIBLE_AXLE: + Scale = 12.0f; + break; + + case LC_SYNTH_PIECE_STRING_BRAIDED: + Scale = 12.0f; + break; + + case LC_SYNTH_PIECE_SHOCK_ABSORBER: + Scale = 1.0f; + break; + } + + float HalfLength = mLength / 2.0f; + Scale = lcMin(Scale, HalfLength); + + if (mType != LC_SYNTH_PIECE_SHOCK_ABSORBER) + { + ControlPoints[0].Transform = lcMatrix44Translation(lcVector3(-HalfLength, 0.0f, 0.0f)); + ControlPoints[1].Transform = lcMatrix44Translation(lcVector3( HalfLength, 0.0f, 0.0f)); + } + else + { + ControlPoints[0].Transform = lcMatrix44Translation(lcVector3(0.0f, 0.0f, -mLength)); + ControlPoints[1].Transform = lcMatrix44Translation(lcVector3(0.0f, 0.0f, 0.0f)); + } + + ControlPoints[0].Scale = Scale; + ControlPoints[1].Scale = Scale; +} + +float lcSynthInfo::GetSectionTwist(const lcMatrix44& StartTransform, const lcMatrix44& EndTransform) const +{ + lcVector3 StartTangent(StartTransform[1].x, StartTransform[1].y, StartTransform[1].z); + lcVector3 EndTangent(EndTransform[1].x, EndTransform[1].y, EndTransform[1].z); + lcVector3 StartUp(StartTransform[2].x, StartTransform[2].y, StartTransform[2].z); + lcVector3 EndUp(EndTransform[2].x, EndTransform[2].y, EndTransform[2].z); + + float TangentDot = lcDot(StartTangent, EndTangent); + float UpDot = lcDot(StartUp, EndUp); + + if (TangentDot > 0.99f && UpDot > 0.99f) + return 0.0f; + + if (fabs(TangentDot) > 0.99f) + { + return acosf(lcClamp(lcDot(EndUp, StartUp), -1.0f, 1.0f)); + } + else if (TangentDot > -0.99f) + { + lcVector3 Axis = lcCross(StartTangent, EndTangent); + float Angle = acosf(lcClamp(TangentDot, -1.0f, 1.0f)); + + lcMatrix33 Rotation = lcMatrix33FromAxisAngle(Axis, Angle); + lcVector3 AdjustedStartUp = lcMul(StartUp, Rotation); + return acosf(lcClamp(lcDot(EndUp, AdjustedStartUp), -1.0f, 1.0f)); + } + + lcVector3 StartSide(StartTransform[0].x, StartTransform[0].y, StartTransform[0].z); + lcVector3 EndSide(EndTransform[0].x, EndTransform[0].y, EndTransform[0].z); + + float SideDot = lcDot(StartSide, EndSide); + + if (fabs(SideDot) < 0.99f) + { + lcVector3 Axis = lcCross(StartSide, EndSide); + float Angle = acosf(SideDot); + + lcMatrix33 Rotation = lcMatrix33FromAxisAngle(Axis, Angle); + lcVector3 AdjustedStartUp = lcMul(StartUp, Rotation); + return acosf(lcClamp(lcDot(EndUp, AdjustedStartUp), -1.0f, 1.0f)); + } + + return 0.0f; +} + +void lcSynthInfo::CalculateCurveSections(const lcArray& ControlPoints, lcArray& Sections, void (*SectionCallback)(const lcVector3& CurvePoint, int SegmentIndex, float t, void* Param), void* CallbackParam) const +{ + float SectionLength = 0.0f; + + for (int ControlPointIdx = 0; ControlPointIdx < ControlPoints.GetSize() - 1 && Sections.GetSize() < mNumSections + 2; ControlPointIdx++) + { + lcVector3 SegmentControlPoints[4]; + + lcMatrix44 StartTransform = lcMatrix44LeoCADToLDraw(ControlPoints[ControlPointIdx].Transform); + lcMatrix44 EndTransform = lcMatrix44LeoCADToLDraw(ControlPoints[ControlPointIdx + 1].Transform); + StartTransform = lcMatrix44(lcMul(lcMul(lcMatrix33(mStart.Transform), lcMatrix33(StartTransform)), lcMatrix33Scale(lcVector3(1.0f, -1.0f, 1.0f))), StartTransform.GetTranslation()); + + if (ControlPointIdx == 0) + { + if (mRigidEdges) + { + StartTransform.SetTranslation(lcMul30(lcVector3(0.0f, mStart.Length, 0.0f), StartTransform) + StartTransform.GetTranslation()); + SectionLength = 0.0f; + } + else + SectionLength = mStart.Length; + + Sections.Add(StartTransform); + } + + EndTransform = lcMatrix44(lcMul(lcMul(lcMatrix33(mEnd.Transform), lcMatrix33(EndTransform)), lcMatrix33Scale(lcVector3(1.0f, -1.0f, 1.0f))), EndTransform.GetTranslation()); + + SegmentControlPoints[0] = StartTransform.GetTranslation(); + SegmentControlPoints[1] = lcMul31(lcVector3(0.0f, ControlPoints[ControlPointIdx].Scale, 0.0f), StartTransform); + SegmentControlPoints[2] = lcMul31(lcVector3(0.0f, -ControlPoints[ControlPointIdx + 1].Scale, 0.0f), EndTransform); + SegmentControlPoints[3] = EndTransform.GetTranslation(); + + const int NumCurvePoints = 8192; + lcArray CurvePoints; + CurvePoints.AllocGrow(NumCurvePoints); + + for (int PointIdx = 0; PointIdx < NumCurvePoints; PointIdx++) + { + float t = (float)PointIdx / (float)(NumCurvePoints - 1); + float it = 1.0f - t; + + lcVector3 Position = it * it * it * SegmentControlPoints[0] + it * it * 3.0f * t * SegmentControlPoints[1] + it * 3.0 * t * t * SegmentControlPoints[2] + t * t * t * SegmentControlPoints[3]; + CurvePoints.Add(Position); + } + + float CurrentSegmentLength = 0.0f; + float TotalSegmentLength = 0.0f; + + for (int PointIdx = 0; PointIdx < CurvePoints.GetSize() - 1; PointIdx++) + TotalSegmentLength += lcLength(CurvePoints[PointIdx] - CurvePoints[PointIdx + 1]); + + lcVector3 StartUp(lcMul30(lcVector3(1.0f, 0.0f, 0.0f), StartTransform)); + float Twist = GetSectionTwist(StartTransform, EndTransform); + int CurrentPointIndex = 0; + + while (CurrentPointIndex < CurvePoints.GetSize() - 1) + { + float Length = lcLength(CurvePoints[CurrentPointIndex + 1] - CurvePoints[CurrentPointIndex]); + CurrentSegmentLength += Length; + SectionLength -= Length; + CurrentPointIndex++; + + if (SectionLength > 0.0f) + continue; + + float t = (float)CurrentPointIndex / (float)(NumCurvePoints - 1); + float it = 1.0f - t; + + lcVector3 Tangent = lcNormalize(-3.0f * it * it * SegmentControlPoints[0] + (3.0f * it * it - 6.0f * t * it) * SegmentControlPoints[1] + (-3.0f * t * t + 6.0f * t * it) * SegmentControlPoints[2] + 3.0f * t * t * SegmentControlPoints[3]); + lcVector3 Up; + + if (Twist) + { + Up = lcMul(StartUp, lcMatrix33FromAxisAngle(Tangent, Twist * (CurrentSegmentLength / TotalSegmentLength))); + CurrentSegmentLength = 0.0f; + } + else + Up = StartUp; + + lcVector3 Side = lcNormalize(lcCross(Tangent, Up)); + Up = lcNormalize(lcCross(Side, Tangent)); + StartUp = Up; + + Sections.Add(lcMatrix44(lcMatrix33(Up, Tangent, Side), CurvePoints[CurrentPointIndex])); + + if (SectionCallback) + SectionCallback(CurvePoints[CurrentPointIndex], ControlPointIdx, t, CallbackParam); + + if (Sections.GetSize() == mNumSections + 2) + break; + + SectionLength += mMiddle.Length; + if (Sections.GetSize() == mNumSections + 1 && !mRigidEdges) + SectionLength += mEnd.Length; + } + } + + while (Sections.GetSize() < mNumSections + 2) + { + lcMatrix44 EndTransform = lcMatrix44LeoCADToLDraw(ControlPoints[ControlPoints.GetSize() - 1].Transform); + EndTransform = lcMatrix44(lcMul(lcMul(lcMatrix33(mEnd.Transform), lcMatrix33(EndTransform)), lcMatrix33Scale(lcVector3(1.0f, -1.0f, 1.0f))), EndTransform.GetTranslation()); + lcVector3 Position = lcMul31(lcVector3(0.0f, SectionLength, 0.0f), EndTransform); + EndTransform.SetTranslation(Position); + Sections.Add(EndTransform); + + if (SectionCallback) + SectionCallback(Position, ControlPoints.GetSize() - 1, 1.0f, CallbackParam); + + SectionLength += mMiddle.Length; + if (Sections.GetSize() == mNumSections + 1 && !mRigidEdges) + SectionLength += mEnd.Length; + } +} + +void lcSynthInfo::CalculateLineSections(const lcArray& ControlPoints, lcArray& Sections, void(*SectionCallback)(const lcVector3& CurvePoint, int SegmentIndex, float t, void* Param), void* CallbackParam) const +{ + for (int ControlPointIdx = 0; ControlPointIdx < ControlPoints.GetSize(); ControlPointIdx++) + { + lcMatrix44 Transform = lcMatrix44LeoCADToLDraw(ControlPoints[ControlPointIdx].Transform); + Sections.Add(Transform); + + if (SectionCallback) + SectionCallback(Transform.GetTranslation(), ControlPointIdx, 1.0f, CallbackParam); + } +} + +void lcSynthInfo::AddRibbedHoseParts(lcMemFile& File, const lcArray& Sections) const +{ + char Line[256]; + + { + const int SectionIdx = 0; + lcMatrix33 Transform(lcMul(lcMatrix33Scale(lcVector3(1.0f, -1.0f, 1.0f)), lcMatrix33(Sections[SectionIdx]))); + lcVector3 Offset = Sections[SectionIdx].GetTranslation(); + + sprintf(Line, "1 16 %f %f %f %f %f %f %f %f %f %f %f %f 79.DAT\n", Offset[0], Offset[1], Offset[2], Transform[0][0], Transform[1][0], Transform[2][0], + Transform[0][1], Transform[1][1], Transform[2][1], Transform[0][2], Transform[1][2], Transform[2][2]); + + File.WriteBuffer(Line, strlen(Line)); + } + + for (int SectionIdx = 1; SectionIdx < Sections.GetSize() - 1; SectionIdx++) + { + const lcMatrix44& Transform = Sections[SectionIdx]; + + sprintf(Line, "1 16 %f %f %f %f %f %f %f %f %f %f %f %f 80.DAT\n", Transform[3][0], Transform[3][1], Transform[3][2], Transform[0][0], Transform[1][0], Transform[2][0], + Transform[0][1], Transform[1][1], Transform[2][1], Transform[0][2], Transform[1][2], Transform[2][2]); + + File.WriteBuffer(Line, strlen(Line)); + } + + { + const int SectionIdx = Sections.GetSize() - 1; + lcMatrix33 Transform(Sections[SectionIdx]); + lcVector3 Offset = lcMul31(lcVector3(0.0f, -6.25f, 0.0f), Sections[SectionIdx]); + + sprintf(Line, "1 16 %f %f %f %f %f %f %f %f %f %f %f %f 79.DAT\n", Offset[0], Offset[1], Offset[2], Transform[0][0], Transform[1][0], Transform[2][0], + Transform[0][1], Transform[1][1], Transform[2][1], Transform[0][2], Transform[1][2], Transform[2][2]); + + File.WriteBuffer(Line, strlen(Line)); + } +} + +void lcSynthInfo::AddFlexibleAxleParts(lcMemFile& File, lcLibraryMeshData& MeshData, const lcArray& Sections) const +{ + char Line[256]; + const int NumEdgeParts = 6; + + lcMatrix33 EdgeTransforms[6] = + { + lcMatrix33(lcVector3(-1.0f, 0.0f, 0.0f), lcVector3(0.0f, -5.0f, 0.0f), lcVector3(0.0f, 0.0f, 1.0f)), + lcMatrix33(lcVector3( 0.0f, 1.0f, 0.0f), lcVector3(1.0f, 0.0f, 0.0f), lcVector3(0.0f, 0.0f, -1.0f)), + lcMatrix33(lcVector3( 0.0f, 1.0f, 0.0f), lcVector3(1.0f, 0.0f, 0.0f), lcVector3(0.0f, 0.0f, -1.0f)), + lcMatrix33(lcVector3( 0.0f, 1.0f, 0.0f), lcVector3(1.0f, 0.0f, 0.0f), lcVector3(0.0f, 0.0f, -1.0f)), + lcMatrix33(lcVector3( 0.0f, 1.0f, 0.0f), lcVector3(1.0f, 0.0f, 0.0f), lcVector3(0.0f, 0.0f, -1.0f)), + lcMatrix33(lcVector3( 0.0f, 1.0f, 0.0f), lcVector3(1.0f, 0.0f, 0.0f), lcVector3(0.0f, 0.0f, -1.0f)), + }; + + const char* EdgeParts[6] = + { + "STUD3A.DAT", "S/FAXLE1.DAT", "S/FAXLE2.DAT", "S/FAXLE3.DAT", "S/FAXLE4.DAT", "S/FAXLE5.DAT" + }; + + for (int PartIdx = 0; PartIdx < NumEdgeParts; PartIdx++) + { + const int SectionIdx = 0; + lcMatrix33 Transform(lcMul(lcMul(EdgeTransforms[PartIdx], lcMatrix33Scale(lcVector3(1.0f, -1.0f, 1.0f))), lcMatrix33(Sections[SectionIdx]))); + lcVector3 Offset = lcMul31(lcVector3(0.0f, -4.0f * (5 - PartIdx), 0.0f), Sections[SectionIdx]); + + sprintf(Line, "1 16 %f %f %f %f %f %f %f %f %f %f %f %f %s\n", Offset[0], Offset[1], Offset[2], Transform[0][0], Transform[1][0], Transform[2][0], + Transform[0][1], Transform[1][1], Transform[2][1], Transform[0][2], Transform[1][2], Transform[2][2], EdgeParts[PartIdx]); + + File.WriteBuffer(Line, strlen(Line)); + } + + for (int PartIdx = 0; PartIdx < NumEdgeParts; PartIdx++) + { + const int SectionIdx = Sections.GetSize() - 1; + lcMatrix33 Transform(lcMul(EdgeTransforms[PartIdx], lcMatrix33(Sections[SectionIdx]))); + lcVector3 Offset = lcMul31(lcVector3(0.0f, 4.0f * (5 - PartIdx), 0.0f), Sections[SectionIdx]); + + sprintf(Line, "1 16 %f %f %f %f %f %f %f %f %f %f %f %f %s\n", Offset[0], Offset[1], Offset[2], Transform[0][0], Transform[1][0], Transform[2][0], + Transform[0][1], Transform[1][1], Transform[2][1], Transform[0][2], Transform[1][2], Transform[2][2], EdgeParts[PartIdx]); + + File.WriteBuffer(Line, strlen(Line)); + } + + lcVector3 SectionVertices[16] = + { + lcVector3(-6.000f, 0.0f, 0.000f), lcVector3(-5.602f, 0.0f, 2.000f), lcVector3(-2.000f, 0.0f, 2.000f), lcVector3(-2.000f, 0.0f, 5.602f), + lcVector3( 0.000f, 0.0f, 6.000f), lcVector3( 2.000f, 0.0f, 5.602f), lcVector3( 2.000f, 0.0f, 2.000f), lcVector3( 5.602f, 0.0f, 2.000f), + lcVector3( 6.000f, 0.0f, 0.000f), lcVector3( 5.602f, 0.0f, -2.000f), lcVector3( 2.000f, 0.0f, -2.000f), lcVector3( 2.000f, 0.0f, -5.602f), + lcVector3( 0.000f, 0.0f, -6.000f), lcVector3(-2.000f, 0.0f, -5.602f), lcVector3(-2.000f, 0.0f, -2.000f), lcVector3(-5.602f, 0.0f, -2.000f) + }; + + int BaseVertex; + lcVertex* VertexBuffer; + lcuint32* IndexBuffer; + MeshData.AddVertices(LC_MESHDATA_SHARED, 16 * (Sections.GetSize() - 1), &BaseVertex, &VertexBuffer); + MeshData.AddIndices(LC_MESHDATA_SHARED, LC_MESH_LINES, 24, 2 * 12 * (Sections.GetSize() - 2), &IndexBuffer); + + for (int SectionIdx = 1; SectionIdx < Sections.GetSize(); SectionIdx++) + { + for (int VertexIdx = 0; VertexIdx < 16; VertexIdx++) + { + VertexBuffer->Position = lcMul31(SectionVertices[VertexIdx], Sections[SectionIdx]); + VertexBuffer++; + } + } + + int BaseLinesVertex = BaseVertex; + + for (int SectionIdx = 1; SectionIdx < Sections.GetSize() - 1; SectionIdx++) + { + for (int VertexIdx = 0; VertexIdx < 16; VertexIdx++) + { + if (VertexIdx % 4) + { + *IndexBuffer++ = BaseLinesVertex; + *IndexBuffer++ = BaseLinesVertex + 16; + } + BaseLinesVertex++; + } + } + + MeshData.AddIndices(LC_MESHDATA_SHARED, LC_MESH_TRIANGLES, 16, 6 * 16 * (Sections.GetSize() - 2), &IndexBuffer); + + for (int SectionIdx = 1; SectionIdx < Sections.GetSize() - 1; SectionIdx++) + { + for (int VertexIdx = 0; VertexIdx < 16; VertexIdx++) + { + int Vertex1 = BaseVertex + VertexIdx; + int Vertex2 = BaseVertex + (VertexIdx + 1) % 16; + + *IndexBuffer++ = Vertex1; + *IndexBuffer++ = Vertex2; + *IndexBuffer++ = Vertex1 + 16; + *IndexBuffer++ = Vertex2; + *IndexBuffer++ = Vertex2 + 16; + *IndexBuffer++ = Vertex1 + 16; + } + BaseVertex += 16; + } +} + +void lcSynthInfo::AddStringBraidedParts(lcMemFile& File, lcLibraryMeshData& MeshData, lcArray& Sections) const +{ + for (int SectionIdx = 0; SectionIdx < Sections.GetSize(); SectionIdx++) + { + lcMatrix33 Transform = lcMul(lcMatrix33(lcVector3(0.0f, 1.0f, 0.0f), lcVector3(1.0f, 0.0f, 0.0f), lcVector3(0.0f, 0.0f, 1.0f)), lcMatrix33(Sections[SectionIdx])); + lcVector3 Offset = Sections[SectionIdx].GetTranslation(); + Sections[SectionIdx] = lcMatrix44(Transform, Offset); + } + + char Line[256]; + + { + const int SectionIdx = 0; + lcMatrix33 Transform(Sections[SectionIdx]); + lcVector3 Offset = lcMul31(lcVector3(-8.0f, 0.0f, 0.0f), Sections[SectionIdx]); + + sprintf(Line, "1 16 %f %f %f %f %f %f %f %f %f %f %f %f 572A.DAT\n", Offset[0], Offset[1], Offset[2], Transform[0][0], Transform[1][0], Transform[2][0], + Transform[0][1], Transform[1][1], Transform[2][1], Transform[0][2], Transform[1][2], Transform[2][2]); + + File.WriteBuffer(Line, strlen(Line)); + } + + const int NumSegments = 16; + const int NumBraids = 4; + const float PositionTable[16] = + { + -1.5f, -1.386f, -1.061f, -0.574f, 0.0f, 0.574f, 1.061f, 1.386f, 1.5f, 1.386f, 1.061f, 0.574f, 0.0f, -0.574f, -1.061f, -1.386f + }; + + int BaseVertex; + lcVertex* VertexBuffer; + lcuint32* IndexBuffer; + MeshData.AddVertices(LC_MESHDATA_SHARED, NumBraids * ((Sections.GetSize() - 2) * NumSegments + 1), &BaseVertex, &VertexBuffer); + MeshData.AddIndices(LC_MESHDATA_SHARED, LC_MESH_LINES, 24, NumBraids * (Sections.GetSize() - 2) * NumSegments * 2, &IndexBuffer); + + for (int BraidIdx = 0; BraidIdx < NumBraids; BraidIdx++) + { + int BaseX = (BraidIdx == 0 || BraidIdx == 2) ? 0 : 8; + int BaseY = (BraidIdx == 0 || BraidIdx == 3) ? 12 : 4; + + for (int SectionIdx = 1; SectionIdx < Sections.GetSize() - 1; SectionIdx++) + { + lcMatrix33 Transform1 = lcMatrix33(Sections[SectionIdx]); + lcMatrix33 Transform2 = lcMatrix33(Sections[SectionIdx + 1]); + lcVector3 Offset1 = Sections[SectionIdx].GetTranslation(); + lcVector3 Offset2 = Sections[SectionIdx + 1].GetTranslation(); + + for (int SegmentIdx = 0; SegmentIdx < ((SectionIdx < Sections.GetSize() - 2) ? NumSegments : NumSegments + 1); SegmentIdx++) + { + float t = (float)SegmentIdx / (float)NumSegments; + + lcVector3 Vertex1 = lcVector3(t * 4.0f, PositionTable[(BaseX + SegmentIdx) % NumSegments], PositionTable[(BaseY + SegmentIdx) % NumSegments]) + lcVector3(0.0f, 1.5f, 0.0f); + lcVector3 Vertex2 = lcVector3((1.0f - t) * -4.0f, PositionTable[(BaseX + SegmentIdx) % NumSegments], PositionTable[(BaseY + SegmentIdx) % NumSegments]) + lcVector3(0.0f, 1.5f, 0.0f); + + lcVector3 Vertex = (lcMul(Vertex1, Transform1) + Offset1) * (1.0f - t) + (lcMul(Vertex2, Transform2) + Offset2) * t; + + VertexBuffer->Position = Vertex; + VertexBuffer++; + + if (SegmentIdx != NumSegments) + { + *IndexBuffer++ = BaseVertex; + *IndexBuffer++ = BaseVertex + 1; + BaseVertex++; + } + } + } + + BaseVertex++; + } + + int NumSlices = 16; + MeshData.AddVertices(LC_MESHDATA_SHARED, NumSlices * ((Sections.GetSize() - 2) * NumSegments + 1), &BaseVertex, &VertexBuffer); + MeshData.AddIndices(LC_MESHDATA_SHARED, LC_MESH_TRIANGLES, 16, NumSlices * (Sections.GetSize() - 2) * NumSegments * 6, &IndexBuffer); + + for (int SectionIdx = 1; SectionIdx < Sections.GetSize() - 1; SectionIdx++) + { + lcMatrix33 Transform1 = lcMatrix33(Sections[SectionIdx]); + lcMatrix33 Transform2 = lcMatrix33(Sections[SectionIdx + 1]); + lcVector3 Offset1 = Sections[SectionIdx].GetTranslation(); + lcVector3 Offset2 = Sections[SectionIdx + 1].GetTranslation(); + + for (int SegmentIdx = 0; SegmentIdx < ((SectionIdx < Sections.GetSize() - 2) ? NumSegments : NumSegments + 1); SegmentIdx++) + { + float t1 = (float)SegmentIdx / (float)NumSegments; + int BaseX = 8; + int BaseY = 4; + + for (int SliceIdx = 0; SliceIdx < NumSlices; SliceIdx++) + { + lcVector3 Vertex11 = lcVector3(t1 * 4.0f, PositionTable[(BaseX + SliceIdx) % NumSlices], PositionTable[(BaseY + SliceIdx) % NumSlices]) + lcVector3(0.0f, 1.5f, 0.0f); + lcVector3 Vertex12 = lcVector3((1.0f - t1) * -4.0f, PositionTable[(BaseX + SliceIdx) % NumSlices], PositionTable[(BaseY + SliceIdx) % NumSlices]) + lcVector3(0.0f, 1.5f, 0.0f); + + lcVector3 Vertex1 = (lcMul(Vertex11, Transform1) + Offset1) * (1.0f - t1) + (lcMul(Vertex12, Transform2) + Offset2) * t1; + + VertexBuffer->Position = Vertex1; + VertexBuffer++; + + if (SegmentIdx != NumSegments) + { + *IndexBuffer++ = BaseVertex + SliceIdx; + *IndexBuffer++ = BaseVertex + (SliceIdx + 1) % NumSlices; + *IndexBuffer++ = BaseVertex + (SliceIdx + 1) % NumSlices + NumSlices; + + *IndexBuffer++ = BaseVertex + SliceIdx + NumSlices; + *IndexBuffer++ = BaseVertex + SliceIdx; + *IndexBuffer++ = BaseVertex + (SliceIdx + 1) % NumSlices + NumSlices; + } + } + + BaseVertex += NumSlices; + } + } + + { + const int SectionIdx = Sections.GetSize() - 1; + lcMatrix33 Transform(Sections[SectionIdx]); + lcVector3 Offset = lcMul31(lcVector3(8.0f, 0.0f, 0.0f), Sections[SectionIdx]); + + sprintf(Line, "1 16 %f %f %f %f %f %f %f %f %f %f %f %f 572A.DAT\n", Offset[0], Offset[1], Offset[2], Transform[0][0], Transform[1][0], Transform[2][0], + Transform[0][1], Transform[1][1], Transform[2][1], Transform[0][2], Transform[1][2], Transform[2][2]); + + File.WriteBuffer(Line, strlen(Line)); + } +} + +void lcSynthInfo::AddShockAbsorberParts(lcMemFile& File, lcArray& Sections) const +{ + char Line[256]; + lcVector3 Offset; + + Offset = Sections[0].GetTranslation(); + sprintf(Line, "1 0 %f %f %f 1 0 0 0 1 0 0 0 1 4254.DAT\n", Offset[0], Offset[1], Offset[2]); + File.WriteBuffer(Line, strlen(Line)); + + Offset = Sections[1].GetTranslation(); + sprintf(Line, "1 16 %f %f %f 1 0 0 0 1 0 0 0 1 4255.DAT\n", Offset[0], Offset[1], Offset[2]); + File.WriteBuffer(Line, strlen(Line)); + + float Distance = Sections[0].GetTranslation().y - Sections[1].GetTranslation().y; + float Scale = (Distance - 66.0f) / 44.0f; + const char* SpringPart; + + if (!strcmp(mPieceInfo->m_strName, "73129")) + SpringPart = "70038"; + else if (!strcmp(mPieceInfo->m_strName, "41838")) + SpringPart = "41837"; + else if (!strcmp(mPieceInfo->m_strName, "76138")) + SpringPart = "71953"; + else if (!strcmp(mPieceInfo->m_strName, "76537")) + SpringPart = "22977"; + else + return; + + Offset = Sections[0].GetTranslation(); + sprintf(Line, "1 494 %f %f %f 1 0 0 0 %f 0 0 0 1 %s.DAT\n", Offset[0], Offset[1] - 10 - 44.0f * Scale, Offset[2], Scale, SpringPart); + File.WriteBuffer(Line, strlen(Line)); +} + +lcMesh* lcSynthInfo::CreateMesh(const lcArray& ControlPoints) const +{ + lcArray Sections; + + if (mCurve) + CalculateCurveSections(ControlPoints, Sections, NULL, NULL); + else + CalculateLineSections(ControlPoints, Sections, NULL, NULL); + + lcLibraryMeshData MeshData; + lcMemFile File; // todo: rewrite this to pass the parts directly + const char* OldLocale = setlocale(LC_NUMERIC, "C"); + + switch (mType) + { + case LC_SYNTH_PIECE_RIBBED_HOSE: + AddRibbedHoseParts(File, Sections); + break; + + case LC_SYNTH_PIECE_FLEXIBLE_AXLE: + AddFlexibleAxleParts(File, MeshData, Sections); + break; + + case LC_SYNTH_PIECE_STRING_BRAIDED: + AddStringBraidedParts(File, MeshData, Sections); + break; + + case LC_SYNTH_PIECE_SHOCK_ABSORBER: + AddShockAbsorberParts(File, Sections); + break; + } + + File.WriteU8(0); + + lcArray TextureStack; + File.Seek(0, SEEK_SET); + + bool Ret = lcGetPiecesLibrary()->ReadMeshData(File, lcMatrix44Identity(), 16, TextureStack, MeshData, LC_MESHDATA_SHARED, false); + setlocale(LC_NUMERIC, OldLocale); + + if (Ret) + return lcGetPiecesLibrary()->CreateMesh(NULL, MeshData); + + return NULL; +} + +struct lcSynthInsertParam +{ + lcVector3 Start; + lcVector3 End; + int BestSegment; + float BestTime; + float BestDistance; + lcVector3 BestPosition; +}; + +static void lcSynthInsertCallback(const lcVector3& CurvePoint, int SegmentIndex, float t, void* Param) +{ + lcSynthInsertParam* SynthInsertParam = (lcSynthInsertParam*)Param; + + float Distance = lcRayPointDistance(CurvePoint, SynthInsertParam->Start, SynthInsertParam->End); + if (Distance < SynthInsertParam->BestDistance) + { + SynthInsertParam->BestSegment = SegmentIndex; + SynthInsertParam->BestTime = t; + SynthInsertParam->BestDistance = Distance; + SynthInsertParam->BestPosition = lcVector3LDrawToLeoCAD(CurvePoint); + } +} + +int lcSynthInfo::InsertControlPoint(lcArray& ControlPoints, const lcVector3& Start, const lcVector3& End) const +{ + lcArray Sections; + lcSynthInsertParam SynthInsertParam; + + SynthInsertParam.Start = Start; + SynthInsertParam.End = End; + SynthInsertParam.BestSegment = -1; + SynthInsertParam.BestDistance = FLT_MAX; + + CalculateCurveSections(ControlPoints, Sections, lcSynthInsertCallback, &SynthInsertParam); + + if (SynthInsertParam.BestSegment != -1) + { + lcPieceControlPoint ControlPoint = ControlPoints[SynthInsertParam.BestSegment]; + ControlPoint.Transform.SetTranslation(SynthInsertParam.BestPosition); + + if (SynthInsertParam.BestSegment != ControlPoints.GetSize() - 1) + { + lcPieceControlPoint NextControlPoint = ControlPoints[SynthInsertParam.BestSegment + 1]; + float t = SynthInsertParam.BestTime; + + ControlPoint.Scale = ControlPoint.Scale * (1.0f - t) + NextControlPoint.Scale * t; + } + + ControlPoints.InsertAt(SynthInsertParam.BestSegment + 1, ControlPoint); + } + + return SynthInsertParam.BestSegment + 1; +} diff --git a/common/lc_synth.h b/common/lc_synth.h index 68ace2f6..27304d78 100644 --- a/common/lc_synth.h +++ b/common/lc_synth.h @@ -1,64 +1,64 @@ -#ifndef _LC_SYNTH_H_ -#define _LC_SYNTH_H_ - -#include "lc_math.h" -#include "piece.h" - -enum lcSynthType -{ - LC_SYNTH_PIECE_RIBBED_HOSE, - LC_SYNTH_PIECE_FLEXIBLE_AXLE, - LC_SYNTH_PIECE_STRING_BRAIDED, - LC_SYNTH_PIECE_SHOCK_ABSORBER -}; - -struct lcSynthComponent -{ - lcMatrix44 Transform; - float Length; -}; - -class lcLibraryMeshData; - -class lcSynthInfo -{ -public: - lcSynthInfo(lcSynthType Type, float Length, int NumSections, PieceInfo* Info); - - bool CanAddControlPoints() const - { - return mCurve; - } - - bool IsCurve() const - { - return mCurve; - } - - void GetDefaultControlPoints(lcArray& ControlPoints) const; - int InsertControlPoint(lcArray& ControlPoints, const lcVector3& Start, const lcVector3& End) const; - lcMesh* CreateMesh(const lcArray& ControlPoints) const; - -protected: - float GetSectionTwist(const lcMatrix44& StartTransform, const lcMatrix44& EndTransform) const; - void CalculateCurveSections(const lcArray& ControlPoints, lcArray& Sections, void(*SectionCallback)(const lcVector3& CurvePoint, int SegmentIndex, float t, void* Param), void* CallbackParam) const; - void CalculateLineSections(const lcArray& ControlPoints, lcArray& Sections, void(*SectionCallback)(const lcVector3& CurvePoint, int SegmentIndex, float t, void* Param), void* CallbackParam) const; - void AddRibbedHoseParts(lcMemFile& File, const lcArray& Sections) const; - void AddFlexibleAxleParts(lcMemFile& File, lcLibraryMeshData& MeshData, const lcArray& Sections) const; - void AddStringBraidedParts(lcMemFile& File, lcLibraryMeshData& MeshData, lcArray& Sections) const; - void AddShockAbsorberParts(lcMemFile& File, lcArray& Sections) const; - - PieceInfo* mPieceInfo; - lcSynthType mType; - lcSynthComponent mStart; - lcSynthComponent mMiddle; - lcSynthComponent mEnd; - bool mCurve; - float mLength; - int mNumSections; - bool mRigidEdges; -}; - -void lcSynthInit(); - -#endif // _LC_SYNTH_H_ +#ifndef _LC_SYNTH_H_ +#define _LC_SYNTH_H_ + +#include "lc_math.h" +#include "piece.h" + +enum lcSynthType +{ + LC_SYNTH_PIECE_RIBBED_HOSE, + LC_SYNTH_PIECE_FLEXIBLE_AXLE, + LC_SYNTH_PIECE_STRING_BRAIDED, + LC_SYNTH_PIECE_SHOCK_ABSORBER +}; + +struct lcSynthComponent +{ + lcMatrix44 Transform; + float Length; +}; + +class lcLibraryMeshData; + +class lcSynthInfo +{ +public: + lcSynthInfo(lcSynthType Type, float Length, int NumSections, PieceInfo* Info); + + bool CanAddControlPoints() const + { + return mCurve; + } + + bool IsCurve() const + { + return mCurve; + } + + void GetDefaultControlPoints(lcArray& ControlPoints) const; + int InsertControlPoint(lcArray& ControlPoints, const lcVector3& Start, const lcVector3& End) const; + lcMesh* CreateMesh(const lcArray& ControlPoints) const; + +protected: + float GetSectionTwist(const lcMatrix44& StartTransform, const lcMatrix44& EndTransform) const; + void CalculateCurveSections(const lcArray& ControlPoints, lcArray& Sections, void(*SectionCallback)(const lcVector3& CurvePoint, int SegmentIndex, float t, void* Param), void* CallbackParam) const; + void CalculateLineSections(const lcArray& ControlPoints, lcArray& Sections, void(*SectionCallback)(const lcVector3& CurvePoint, int SegmentIndex, float t, void* Param), void* CallbackParam) const; + void AddRibbedHoseParts(lcMemFile& File, const lcArray& Sections) const; + void AddFlexibleAxleParts(lcMemFile& File, lcLibraryMeshData& MeshData, const lcArray& Sections) const; + void AddStringBraidedParts(lcMemFile& File, lcLibraryMeshData& MeshData, lcArray& Sections) const; + void AddShockAbsorberParts(lcMemFile& File, lcArray& Sections) const; + + PieceInfo* mPieceInfo; + lcSynthType mType; + lcSynthComponent mStart; + lcSynthComponent mMiddle; + lcSynthComponent mEnd; + bool mCurve; + float mLength; + int mNumSections; + bool mRigidEdges; +}; + +void lcSynthInit(); + +#endif // _LC_SYNTH_H_ diff --git a/common/lc_timelinewidget.cpp b/common/lc_timelinewidget.cpp index 55f9aec4..695ea66d 100644 --- a/common/lc_timelinewidget.cpp +++ b/common/lc_timelinewidget.cpp @@ -1,344 +1,344 @@ -#include "lc_global.h" -#include "lc_timelinewidget.h" -#include "lc_model.h" -#include "project.h" -#include "piece.h" -#include "pieceinf.h" -#include "lc_mainwindow.h" - -lcTimelineWidget::lcTimelineWidget(QWidget* Parent) - : QTreeWidget(Parent) -{ - mIgnoreUpdates = false; - - setSelectionMode(QAbstractItemView::ExtendedSelection); - setDragEnabled(true); - setDragDropMode(QAbstractItemView::InternalMove); - setUniformRowHeights(true); - setHeaderHidden(true); - setContextMenuPolicy(Qt::CustomContextMenu); - - invisibleRootItem()->setFlags(invisibleRootItem()->flags() & ~Qt::ItemIsDropEnabled); - - connect(this, SIGNAL(itemSelectionChanged()), SLOT(ItemSelectionChanged())); - connect(this, SIGNAL(customContextMenuRequested(QPoint)), SLOT(CustomMenuRequested(QPoint))); -} - -lcTimelineWidget::~lcTimelineWidget() -{ -} - -void lcTimelineWidget::CustomMenuRequested(QPoint Pos) -{ - QMenu* Menu = new QMenu(this); - - lcObject* FocusObject = lcGetActiveModel()->GetFocusObject(); - - if (FocusObject && FocusObject->IsPiece()) - { - lcPiece* Piece = (lcPiece*)FocusObject; - - if (Piece->mPieceInfo->IsModel()) - { - Menu->addAction(gMainWindow->mActions[LC_MODEL_EDIT_FOCUS]); - Menu->addSeparator(); - } - } - - QAction* InsertStepAction = Menu->addAction(gMainWindow->mActions[LC_VIEW_TIME_INSERT]->text(), this, SLOT(InsertStep())); - InsertStepAction->setStatusTip(gMainWindow->mActions[LC_VIEW_TIME_INSERT]->statusTip()); - QAction* RemoveStepAction = Menu->addAction(gMainWindow->mActions[LC_VIEW_TIME_DELETE]->text(), this, SLOT(RemoveStep())); - RemoveStepAction->setStatusTip(gMainWindow->mActions[LC_VIEW_TIME_DELETE]->statusTip()); - Menu->addSeparator(); - - Menu->addAction(gMainWindow->mActions[LC_PIECE_HIDE_SELECTED]); - Menu->addAction(gMainWindow->mActions[LC_PIECE_HIDE_UNSELECTED]); - Menu->addAction(gMainWindow->mActions[LC_PIECE_UNHIDE_SELECTED]); - Menu->addAction(gMainWindow->mActions[LC_PIECE_UNHIDE_ALL]); - - Menu->popup(viewport()->mapToGlobal(Pos)); -} - -void lcTimelineWidget::Update(bool Clear, bool UpdateItems) -{ - if (mIgnoreUpdates) - return; - - lcModel* Model = lcGetActiveModel(); - - if (!Model) - { - mItems.clear(); - clear(); - return; - } - - bool Blocked = blockSignals(true); - - if (Clear) - { - mItems.clear(); - clear(); - } - - lcStep LastStep = lcMax(Model->GetLastStep(), Model->GetCurrentStep()); - - for (int TopLevelItemIdx = LastStep; TopLevelItemIdx < topLevelItemCount(); ) - { - QTreeWidgetItem* StepItem = topLevelItem(TopLevelItemIdx); - - while (StepItem->childCount()) - { - QTreeWidgetItem* PieceItem = StepItem->child(0); - lcPiece* Piece = (lcPiece*)PieceItem->data(0, Qt::UserRole).value(); - mItems.remove(Piece); - delete PieceItem; - } - - delete StepItem; - } - - for (unsigned int TopLevelItemIdx = topLevelItemCount(); TopLevelItemIdx < LastStep; TopLevelItemIdx++) - { - QTreeWidgetItem* StepItem = new QTreeWidgetItem(this, QStringList(tr("Step %1").arg(TopLevelItemIdx + 1))); - StepItem->setFlags(Qt::ItemIsEnabled | Qt::ItemIsDropEnabled); - addTopLevelItem(StepItem); - StepItem->setExpanded(true); - } - - const lcArray& Pieces = Model->GetPieces(); - QTreeWidgetItem* StepItem = NULL; - int PieceItemIndex = 0; - lcStep Step = 0; - - for (int PieceIdx = 0; PieceIdx != Pieces.GetSize(); PieceIdx++) - { - lcPiece* Piece = Pieces[PieceIdx]; - - while (Step != Piece->GetStepShow()) - { - if (StepItem) - { - while (PieceItemIndex < StepItem->childCount()) - { - QTreeWidgetItem* PieceItem = StepItem->child(PieceItemIndex); - lcPiece* RemovePiece = (lcPiece*)PieceItem->data(0, Qt::UserRole).value(); - - if (Pieces.FindIndex(RemovePiece) == -1) - { - mItems.remove(RemovePiece); - delete PieceItem; - } - else - { - PieceItem->parent()->removeChild(PieceItem); - topLevelItem(RemovePiece->GetStepShow() - 1)->addChild(PieceItem); - } - } - } - - Step++; - StepItem = topLevelItem(Step - 1); - PieceItemIndex = 0; - } - - QTreeWidgetItem* PieceItem = mItems.value(Piece); - bool UpdateItem = UpdateItems; - - if (!PieceItem) - { - PieceItem = new QTreeWidgetItem(); - PieceItem->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsDragEnabled); - PieceItem->setData(0, Qt::UserRole, qVariantFromValue((uintptr_t)Piece)); - StepItem->insertChild(PieceItemIndex, PieceItem); - mItems[Piece] = PieceItem; - - UpdateItem = true; - } - else - { - if (PieceItemIndex >= StepItem->childCount() || PieceItem != StepItem->child(PieceItemIndex)) - { - QTreeWidgetItem* PieceParent = PieceItem->parent(); - - if (PieceParent) - PieceParent->removeChild(PieceItem); - - StepItem->insertChild(PieceItemIndex, PieceItem); - } - } - - if (UpdateItem) - { - PieceItem->setText(0, Piece->mPieceInfo->m_strDescription); - - int ColorIndex = Piece->mColorIndex; - if (!mIcons.contains(ColorIndex)) - { - int Size = rowHeight(indexFromItem(PieceItem)); - - QImage Image(Size, Size, QImage::Format_ARGB32); - Image.fill(0); - float* Color = gColorList[ColorIndex].Value; - QPainter Painter(&Image); - Painter.setPen(Qt::NoPen); - Painter.setBrush(QColor::fromRgbF(Color[0], Color[1], Color[2])); - Painter.drawEllipse(QPoint(Size / 2, Size / 2), Size / 2, Size / 2); - - mIcons[ColorIndex] = QIcon(QPixmap::fromImage(Image)); - } - - PieceItem->setIcon(0, mIcons[ColorIndex]); - - QColor Color = palette().text().color(); - if (Piece->IsHidden()) - Color.setAlpha(128); - PieceItem->setTextColor(0, Color); - } - - PieceItem->setSelected(Piece->IsSelected()); - PieceItemIndex++; - } - - if (Step == 0) - { - Step = 1; - StepItem = topLevelItem(0); - } - - while (Step <= LastStep) - { - while (PieceItemIndex < StepItem->childCount()) - { - QTreeWidgetItem* PieceItem = StepItem->child(PieceItemIndex); - lcPiece* RemovePiece = (lcPiece*)PieceItem->data(0, Qt::UserRole).value(); - - mItems.remove(RemovePiece); - delete PieceItem; - } - - Step++; - StepItem = topLevelItem(Step - 1); - PieceItemIndex = 0; - } - - blockSignals(Blocked); -} - -void lcTimelineWidget::UpdateSelection() -{ - if (mIgnoreUpdates) - return; - - QItemSelection ItemSelection; - - for (int TopLevelItemIdx = 0; TopLevelItemIdx < topLevelItemCount(); TopLevelItemIdx++) - { - QTreeWidgetItem* StepItem = topLevelItem(TopLevelItemIdx); - - for (int PieceItemIdx = 0; PieceItemIdx < StepItem->childCount(); PieceItemIdx++) - { - QTreeWidgetItem* PieceItem = StepItem->child(PieceItemIdx); - lcPiece* Piece = (lcPiece*)PieceItem->data(0, Qt::UserRole).value(); - - if (Piece->IsSelected()) - { - QModelIndex Index = indexFromItem(PieceItem); - ItemSelection.select(Index, Index); - } - } - } - - bool Blocked = blockSignals(true); - - selectionModel()->select(ItemSelection, QItemSelectionModel::ClearAndSelect); - - blockSignals(Blocked); -} - -void lcTimelineWidget::InsertStep() -{ - QTreeWidgetItem* CurrentItem = currentItem(); - - if (!CurrentItem) - return; - - if (CurrentItem->parent()) - CurrentItem = CurrentItem->parent(); - - int Step = indexOfTopLevelItem(CurrentItem); - - if (Step == -1) - return; - - lcGetActiveModel()->InsertStep(Step + 1); -} - -void lcTimelineWidget::RemoveStep() -{ - QTreeWidgetItem* CurrentItem = currentItem(); - - if (!CurrentItem) - return; - - if (CurrentItem->parent()) - CurrentItem = CurrentItem->parent(); - - int Step = indexOfTopLevelItem(CurrentItem); - - if (Step == -1) - return; - - lcGetActiveModel()->RemoveStep(Step + 1); -} - -void lcTimelineWidget::ItemSelectionChanged() -{ - lcArray Selection; - lcStep LastStep = 1; - - foreach (QTreeWidgetItem* PieceItem, selectedItems()) - { - lcPiece* Piece = (lcPiece*)PieceItem->data(0, Qt::UserRole).value(); - LastStep = lcMax(LastStep, Piece->GetStepShow()); - Selection.Add(Piece); - } - - lcPiece* CurrentPiece = NULL; - QTreeWidgetItem* CurrentItem = currentItem(); - if (CurrentItem && CurrentItem->isSelected()) - CurrentPiece = (lcPiece*)CurrentItem->data(0, Qt::UserRole).value(); - - bool Blocked = blockSignals(true); - mIgnoreUpdates = true; - lcModel* Model = lcGetActiveModel(); - if (LastStep > Model->GetCurrentStep()) - Model->SetCurrentStep(LastStep); - Model->SetSelectionAndFocus(Selection, CurrentPiece, LC_PIECE_SECTION_POSITION); - mIgnoreUpdates = false; - blockSignals(Blocked); -} - -void lcTimelineWidget::dropEvent(QDropEvent* Event) -{ - QTreeWidget::dropEvent(Event); - - QList> PieceSteps; - - for (int TopLevelItemIdx = 0; TopLevelItemIdx < topLevelItemCount(); TopLevelItemIdx++) - { - QTreeWidgetItem* StepItem = topLevelItem(TopLevelItemIdx); - - for (int PieceItemIdx = 0; PieceItemIdx < StepItem->childCount(); PieceItemIdx++) - { - QTreeWidgetItem* PieceItem = StepItem->child(PieceItemIdx); - lcPiece* Piece = (lcPiece*)PieceItem->data(0, Qt::UserRole).value(); - - PieceSteps.append(QPair(Piece, TopLevelItemIdx + 1)); - } - } - - mIgnoreUpdates = true; - lcGetActiveModel()->SetPieceSteps(PieceSteps); - mIgnoreUpdates = false; -} +#include "lc_global.h" +#include "lc_timelinewidget.h" +#include "lc_model.h" +#include "project.h" +#include "piece.h" +#include "pieceinf.h" +#include "lc_mainwindow.h" + +lcTimelineWidget::lcTimelineWidget(QWidget* Parent) + : QTreeWidget(Parent) +{ + mIgnoreUpdates = false; + + setSelectionMode(QAbstractItemView::ExtendedSelection); + setDragEnabled(true); + setDragDropMode(QAbstractItemView::InternalMove); + setUniformRowHeights(true); + setHeaderHidden(true); + setContextMenuPolicy(Qt::CustomContextMenu); + + invisibleRootItem()->setFlags(invisibleRootItem()->flags() & ~Qt::ItemIsDropEnabled); + + connect(this, SIGNAL(itemSelectionChanged()), SLOT(ItemSelectionChanged())); + connect(this, SIGNAL(customContextMenuRequested(QPoint)), SLOT(CustomMenuRequested(QPoint))); +} + +lcTimelineWidget::~lcTimelineWidget() +{ +} + +void lcTimelineWidget::CustomMenuRequested(QPoint Pos) +{ + QMenu* Menu = new QMenu(this); + + lcObject* FocusObject = lcGetActiveModel()->GetFocusObject(); + + if (FocusObject && FocusObject->IsPiece()) + { + lcPiece* Piece = (lcPiece*)FocusObject; + + if (Piece->mPieceInfo->IsModel()) + { + Menu->addAction(gMainWindow->mActions[LC_MODEL_EDIT_FOCUS]); + Menu->addSeparator(); + } + } + + QAction* InsertStepAction = Menu->addAction(gMainWindow->mActions[LC_VIEW_TIME_INSERT]->text(), this, SLOT(InsertStep())); + InsertStepAction->setStatusTip(gMainWindow->mActions[LC_VIEW_TIME_INSERT]->statusTip()); + QAction* RemoveStepAction = Menu->addAction(gMainWindow->mActions[LC_VIEW_TIME_DELETE]->text(), this, SLOT(RemoveStep())); + RemoveStepAction->setStatusTip(gMainWindow->mActions[LC_VIEW_TIME_DELETE]->statusTip()); + Menu->addSeparator(); + + Menu->addAction(gMainWindow->mActions[LC_PIECE_HIDE_SELECTED]); + Menu->addAction(gMainWindow->mActions[LC_PIECE_HIDE_UNSELECTED]); + Menu->addAction(gMainWindow->mActions[LC_PIECE_UNHIDE_SELECTED]); + Menu->addAction(gMainWindow->mActions[LC_PIECE_UNHIDE_ALL]); + + Menu->popup(viewport()->mapToGlobal(Pos)); +} + +void lcTimelineWidget::Update(bool Clear, bool UpdateItems) +{ + if (mIgnoreUpdates) + return; + + lcModel* Model = lcGetActiveModel(); + + if (!Model) + { + mItems.clear(); + clear(); + return; + } + + bool Blocked = blockSignals(true); + + if (Clear) + { + mItems.clear(); + clear(); + } + + lcStep LastStep = lcMax(Model->GetLastStep(), Model->GetCurrentStep()); + + for (int TopLevelItemIdx = LastStep; TopLevelItemIdx < topLevelItemCount(); ) + { + QTreeWidgetItem* StepItem = topLevelItem(TopLevelItemIdx); + + while (StepItem->childCount()) + { + QTreeWidgetItem* PieceItem = StepItem->child(0); + lcPiece* Piece = (lcPiece*)PieceItem->data(0, Qt::UserRole).value(); + mItems.remove(Piece); + delete PieceItem; + } + + delete StepItem; + } + + for (unsigned int TopLevelItemIdx = topLevelItemCount(); TopLevelItemIdx < LastStep; TopLevelItemIdx++) + { + QTreeWidgetItem* StepItem = new QTreeWidgetItem(this, QStringList(tr("Step %1").arg(TopLevelItemIdx + 1))); + StepItem->setFlags(Qt::ItemIsEnabled | Qt::ItemIsDropEnabled); + addTopLevelItem(StepItem); + StepItem->setExpanded(true); + } + + const lcArray& Pieces = Model->GetPieces(); + QTreeWidgetItem* StepItem = NULL; + int PieceItemIndex = 0; + lcStep Step = 0; + + for (int PieceIdx = 0; PieceIdx != Pieces.GetSize(); PieceIdx++) + { + lcPiece* Piece = Pieces[PieceIdx]; + + while (Step != Piece->GetStepShow()) + { + if (StepItem) + { + while (PieceItemIndex < StepItem->childCount()) + { + QTreeWidgetItem* PieceItem = StepItem->child(PieceItemIndex); + lcPiece* RemovePiece = (lcPiece*)PieceItem->data(0, Qt::UserRole).value(); + + if (Pieces.FindIndex(RemovePiece) == -1) + { + mItems.remove(RemovePiece); + delete PieceItem; + } + else + { + PieceItem->parent()->removeChild(PieceItem); + topLevelItem(RemovePiece->GetStepShow() - 1)->addChild(PieceItem); + } + } + } + + Step++; + StepItem = topLevelItem(Step - 1); + PieceItemIndex = 0; + } + + QTreeWidgetItem* PieceItem = mItems.value(Piece); + bool UpdateItem = UpdateItems; + + if (!PieceItem) + { + PieceItem = new QTreeWidgetItem(); + PieceItem->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsDragEnabled); + PieceItem->setData(0, Qt::UserRole, qVariantFromValue((uintptr_t)Piece)); + StepItem->insertChild(PieceItemIndex, PieceItem); + mItems[Piece] = PieceItem; + + UpdateItem = true; + } + else + { + if (PieceItemIndex >= StepItem->childCount() || PieceItem != StepItem->child(PieceItemIndex)) + { + QTreeWidgetItem* PieceParent = PieceItem->parent(); + + if (PieceParent) + PieceParent->removeChild(PieceItem); + + StepItem->insertChild(PieceItemIndex, PieceItem); + } + } + + if (UpdateItem) + { + PieceItem->setText(0, Piece->mPieceInfo->m_strDescription); + + int ColorIndex = Piece->mColorIndex; + if (!mIcons.contains(ColorIndex)) + { + int Size = rowHeight(indexFromItem(PieceItem)); + + QImage Image(Size, Size, QImage::Format_ARGB32); + Image.fill(0); + float* Color = gColorList[ColorIndex].Value; + QPainter Painter(&Image); + Painter.setPen(Qt::NoPen); + Painter.setBrush(QColor::fromRgbF(Color[0], Color[1], Color[2])); + Painter.drawEllipse(QPoint(Size / 2, Size / 2), Size / 2, Size / 2); + + mIcons[ColorIndex] = QIcon(QPixmap::fromImage(Image)); + } + + PieceItem->setIcon(0, mIcons[ColorIndex]); + + QColor Color = palette().text().color(); + if (Piece->IsHidden()) + Color.setAlpha(128); + PieceItem->setTextColor(0, Color); + } + + PieceItem->setSelected(Piece->IsSelected()); + PieceItemIndex++; + } + + if (Step == 0) + { + Step = 1; + StepItem = topLevelItem(0); + } + + while (Step <= LastStep) + { + while (PieceItemIndex < StepItem->childCount()) + { + QTreeWidgetItem* PieceItem = StepItem->child(PieceItemIndex); + lcPiece* RemovePiece = (lcPiece*)PieceItem->data(0, Qt::UserRole).value(); + + mItems.remove(RemovePiece); + delete PieceItem; + } + + Step++; + StepItem = topLevelItem(Step - 1); + PieceItemIndex = 0; + } + + blockSignals(Blocked); +} + +void lcTimelineWidget::UpdateSelection() +{ + if (mIgnoreUpdates) + return; + + QItemSelection ItemSelection; + + for (int TopLevelItemIdx = 0; TopLevelItemIdx < topLevelItemCount(); TopLevelItemIdx++) + { + QTreeWidgetItem* StepItem = topLevelItem(TopLevelItemIdx); + + for (int PieceItemIdx = 0; PieceItemIdx < StepItem->childCount(); PieceItemIdx++) + { + QTreeWidgetItem* PieceItem = StepItem->child(PieceItemIdx); + lcPiece* Piece = (lcPiece*)PieceItem->data(0, Qt::UserRole).value(); + + if (Piece->IsSelected()) + { + QModelIndex Index = indexFromItem(PieceItem); + ItemSelection.select(Index, Index); + } + } + } + + bool Blocked = blockSignals(true); + + selectionModel()->select(ItemSelection, QItemSelectionModel::ClearAndSelect); + + blockSignals(Blocked); +} + +void lcTimelineWidget::InsertStep() +{ + QTreeWidgetItem* CurrentItem = currentItem(); + + if (!CurrentItem) + return; + + if (CurrentItem->parent()) + CurrentItem = CurrentItem->parent(); + + int Step = indexOfTopLevelItem(CurrentItem); + + if (Step == -1) + return; + + lcGetActiveModel()->InsertStep(Step + 1); +} + +void lcTimelineWidget::RemoveStep() +{ + QTreeWidgetItem* CurrentItem = currentItem(); + + if (!CurrentItem) + return; + + if (CurrentItem->parent()) + CurrentItem = CurrentItem->parent(); + + int Step = indexOfTopLevelItem(CurrentItem); + + if (Step == -1) + return; + + lcGetActiveModel()->RemoveStep(Step + 1); +} + +void lcTimelineWidget::ItemSelectionChanged() +{ + lcArray Selection; + lcStep LastStep = 1; + + foreach (QTreeWidgetItem* PieceItem, selectedItems()) + { + lcPiece* Piece = (lcPiece*)PieceItem->data(0, Qt::UserRole).value(); + LastStep = lcMax(LastStep, Piece->GetStepShow()); + Selection.Add(Piece); + } + + lcPiece* CurrentPiece = NULL; + QTreeWidgetItem* CurrentItem = currentItem(); + if (CurrentItem && CurrentItem->isSelected()) + CurrentPiece = (lcPiece*)CurrentItem->data(0, Qt::UserRole).value(); + + bool Blocked = blockSignals(true); + mIgnoreUpdates = true; + lcModel* Model = lcGetActiveModel(); + if (LastStep > Model->GetCurrentStep()) + Model->SetCurrentStep(LastStep); + Model->SetSelectionAndFocus(Selection, CurrentPiece, LC_PIECE_SECTION_POSITION); + mIgnoreUpdates = false; + blockSignals(Blocked); +} + +void lcTimelineWidget::dropEvent(QDropEvent* Event) +{ + QTreeWidget::dropEvent(Event); + + QList> PieceSteps; + + for (int TopLevelItemIdx = 0; TopLevelItemIdx < topLevelItemCount(); TopLevelItemIdx++) + { + QTreeWidgetItem* StepItem = topLevelItem(TopLevelItemIdx); + + for (int PieceItemIdx = 0; PieceItemIdx < StepItem->childCount(); PieceItemIdx++) + { + QTreeWidgetItem* PieceItem = StepItem->child(PieceItemIdx); + lcPiece* Piece = (lcPiece*)PieceItem->data(0, Qt::UserRole).value(); + + PieceSteps.append(QPair(Piece, TopLevelItemIdx + 1)); + } + } + + mIgnoreUpdates = true; + lcGetActiveModel()->SetPieceSteps(PieceSteps); + mIgnoreUpdates = false; +} diff --git a/resources/application-vnd.leocad.svg b/resources/application-vnd.leocad.svg index bc38ee95..de84af58 100644 --- a/resources/application-vnd.leocad.svg +++ b/resources/application-vnd.leocad.svg @@ -1,782 +1,782 @@ - - - - - + + + + + diff --git a/resources/leocad.svg b/resources/leocad.svg index bc38ee95..de84af58 100644 --- a/resources/leocad.svg +++ b/resources/leocad.svg @@ -1,782 +1,782 @@ - - - - - + + + + + diff --git a/resources/minifig.ini b/resources/minifig.ini index 2d03147b..5d1fae6d 100644 --- a/resources/minifig.ini +++ b/resources/minifig.ini @@ -1,1809 +1,1809 @@ -; Version 2015-02 - -[HATS] -"Cap Aviator" "30171.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Cap Aviator with Black Goggles" "30171C01.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Cap with Long Flat Peak" "4485.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Cap with Short Arched Peak" "86035.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Cap with Short Arched Peak with Seams" "11303.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Cap with Short Arched Peak and Black Headphones" "11303C01.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Castle Helmet with Chin-Guard" "3896.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Castle Helmet with Neck Protector" "3844.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Construction Helmet" "3833.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Cook's Hat" "3898.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Fire Helmet" "3834.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Fire Helmet Breathing Hose" "6158.DAT" 0 1 0 0 0 1 0 0 0 1 0 24 0 -"Fire Helmet with Fire Logo Shield Pattern" "3834p01.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Forestman Cap" "4506.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Forestman Cap with Small Red Plume (Complete)" "4506C01.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Friends Hair Long Straight" "92255.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Friends Hair Long Wavy" "92256.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Friends Hair Long Wavy Partially Tied Back" "92258.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Friends Hair Long with Curls" "93352.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Friends Hair Long w. Ponytail French Braided w. 3 Holes" "15675.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Friends Hair Long w. Ponytail and Side Bangs" "92257.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Friends Hair Long w. Ponytail, Side Bangs a. Riding Helmet" "92254.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Friends Hair Long w. Ponytail, Side Bangs a. BL Riding Helmet""92254P01.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Friends Hair Long w. Ponytail, Side Bangs a. Sun Visor" "15284.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Friends Hair Long w. Ponytail, Side Bangs a. Dk Pink Sun Visor""15284P01.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Friends Hair Short, Bob Cut" "92259.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Friends Hair Wavy w. Curls and 2 Pinholes" "15677.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Friends Hair w. Top Knot Bun and Hair Band" "15673.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Friends Hair w. Top Knot Bun and Medium Blue Hair Band" "15673P01.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Ghost Shroud" "2588.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Hair Backslick" "64798.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Hair Bubble Style (Afro)" "87995.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Hair Combed Front to Rear" "92081.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Hair Female with Pigtails" "3625.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Hair Flat Top" "30608.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Hair Islander" "6025.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Hair Male" "3901.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Hair Long and Half Braided" "30475.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Hair Long Straight" "40239.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Hair Long with French Braid" "59363.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Hair Long with Headband" "30114.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Hair Long with Headband and Feathers (Complete)" "30114C01.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Hair Long with One Front Lock" "85974.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Hair Long Wavy" "40251.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 - -; Update 2015-01 -"Hair Orc with Dark Tan Ears Pattern" "10066P01.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Hair Orc with Ears" "10066.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Hair Orc with Medium Dark Flesh Ears Pattern" "10066P02.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Hair Orc with Olive Green Ears Pattern" "10066P03.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 - -"Hair Peaked" "42444.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Hair Ponytail" "6093a.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Hair Ponytail with Long Bangs" "62696.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Hair Pulled Back" "92756.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Hair Short Tousled" "40233.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Hair Short, Tousled with Side Parting" "62810.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Hair Shoulder Length" "4530.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Hair Spiky Long" "53982.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Hair Spiky Short" "53981.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Hair Straight Cut with Short Ponytail" "17630.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Hair Swept Back Into Bun" "99240.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Hair Swept Back Tousled" "61183.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Hair Swept Right with Front Curl" "98726.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Hair Tousled" "10048.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Hair Wavy" "43751.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 - -; Update 2015-01 -"Hair with Snakes" "12889.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 - -"Hair with Two Buns" "30409.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Hair with Two Locks on Left Side" "15443.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Hat Bicorne" "2528.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Hat Bicorne with Evil Skull and Crossbones Pattern" "2528P30.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Hat Bowler" "95674.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Hat Bowler with Red Flower with Yellow Centre Pattern" "95674P01.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Hat Conical Asian" "93059.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Hat Cowboy" "3629.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Hat Cowboy with Cavalry Logo Pattern" "3629PW1.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Hat Cowboy with Silver Star Pattern" "3629PW2.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Hat Crown" "71015.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Hat Elf with Pointy Ears" "13787.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Hat Elf with Pointy Ears with Bright Green Top Pattern" "13787P01.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Hat Fedora" "61506.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Hat Fez" "85975.dat" 0 1 0 0 0 1 0 0 0 1 0 -14 0 -"Hat Imperial Guard Shako" "2545.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Hat High Cone Shaped" "2338.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Hat Kepi" "30135.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Hat Knit Cap" "41334.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Hat Pith Helmet" "30172.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Hat Rag" "2543.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Hat Tricorne" "2544.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Hat Tricorne with Plume (Complete)" "2544C01.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Hat Wide Brim Flat" "30167.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Hat with Wide Brim Down" "13788.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Headdress Aztec Bird" "99243.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Headdress Aztec Bird with Eyes and Cheeks Pattern" "99243P01.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Headdress Batman" "55704.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Headdress Catwoman" "98729.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Headdress Horus" "93249.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Headdress Horus with Eye Pattern" "93249PQ0.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Headdress Nemes Type 1" "30168.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Headdress Nemes Type 2" "90462.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Headdress Nemes with 2 Darkblue Snakes Pattern" "90462PQ0.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Headdress Nemes with Darkblue Stripes Pattern" "90462PQ1.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Headdress SW Zabrak Horns" "92761.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Headdress Turban" "40235.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Headdress Werewolf" "42443.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Helmet Army" "87998.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Helmet Army with White Stencil Cross Pattern" "87998p01.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Helmet Alien Skull with Fangs" "85945.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Helmet Cap" "60748.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Helmet Cap with Wings" "60747.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Helmet Castle Rohan w. Cheek Protection & Comb" "10054.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Helmet Castle Rohan w. Cheek Prot. & Comb w. Eomer Pat." "10054P01.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Helmet Castle Rohan w. Cheek Prot. & Comb w. Theoden Pat." "10054P02.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Helmet Castle Uruk-Hai with Lateral Comb" "10051.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Helmet Castle Uruk-Hai with Lateral Comb & Hand Pattern" "10051P01.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Helmet Castle with Dragon Crown Top" "6122.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Helmet Castle with Angled Cheek Protection" "48493.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Helmet Castle w. Dragon Crown Top Black w. Dragon Plume" "6122c01.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Helmet Castle w. Dragon Crown Top w. Cattlehorn White" "6122c02.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Helmet Castle with Fixed Face Grille" "4503.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Helmet Classic with Thin Chin Guard" "3842a.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Helmet Classic with Thick Chin Guard" "3842b.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Helmet Darth Vader" "30368.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Helmet Gladiator" "95676.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Helmet Imperial AT-ST Pilot" "57900.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Helmet Iron Man" "10907.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Helmet Iron Man w. Visor w. Gold Face, White Eyes Pattern" "10907C01.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Helmet Modern" "2446.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Helmet Modern with Black, Blue and Silver Unitron Pattern" "2446P51.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Helmet Modern with Blue and Silver Spyrius Pattern" "2446P50.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Helmet Modern with One Red and Two Green Stripes Pattern" "2446P01.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Helmet Morion" "30048.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Helmet Persian" "88284.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Helmet Samurai" "30175.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Helmet Samurai with Horn (Shortcut)" "30175c01.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Helmet Scout Trooper" "30369.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Helmet Skateboard" "46303.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Helmet Stormtrooper" "30408.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Helmet Stormtrooper with Stormtrooper Pattern" "30408p01.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Helmet Stormtrooper with TIE-Fighter Pilot Pattern" "30408p02.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Helmet SW Rebel Pilot" "30370.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Helmet SW Rebel Pilot with Blue Rebel Logo Pattern" "30370ps3.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Helmet SW Rebel Pilot with Checkered Pattern" "30370ps4.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Helmet SW Rebel Pilot with Red Rebel Logo Pattern" "30370ps2.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Helmet SW Rebel Pilot with Yellow Grid on Bley Pattern" "30370ps1.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Helmet SW Rebel Pilot with Yellow Grid on Grey Pattern" "30370ps5.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Helmet Viking with Horns" "53450C01.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Helmet Viking with Nose Protector" "53450.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Helmet with Bat Wings" "30105.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Helmet with Chinstrap and Wide Brim" "30273.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Helmet with Front Prongs" "10305.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Helmet with Front Prongs w. Dark Purple Highlight Pattern" "10305P01.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Helmet with Hexagonal Top, Hoses" "30120.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Helmet with Hexagonal Top, Hoses, Gold Alien Pattern" "30120P01.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Helmet with Hexagonal Top, Hoses, Silver Alien Pattern" "30120P02.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Hood" "30381.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Hood Medieval Cowl" "4505a.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Jester's Cap" "62537.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Jester's Cap with Black Half and White Poms Pattern" "62537p02.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Jester's Cap with Blue Half and Blue Pom Pattern" "62537p01.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Jester's Cap with Red Half and Red Pom Pattern" "62537p03.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Mask Wolf" "11233.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Mask Wolf with Fangs, Scars and White Ears Pattern" "11233P01.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Police Hat" "3624.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Police Helmet" "13789.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Police Helmet with Silver Badge Pattern" "13789P01.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Top Hat" "3878.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Wizards Hat" "6131.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"--------------------------------------------------------------------------------" "" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"None" "" 0 1 0 0 0 1 0 0 0 1 0 0 0 - - - -[HATS2] -"None" "" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Cap Aviator Goggles" "30170.DAT" 0 1 0 0 0 1 0 0 0 1 0 8 0 -"Cattlehorns (repositioning may needed)" "87695.DAT" 0 1 0 0 0 1 0 0 0 1 0 -6 -18 -"Diver Mask" "30090.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 - -; Update 2015-01 -"Feathered Headdress Small" "87696.DAT" 0 1 0 0 0 1 0 0 0 1 0 -12 0 - -"Feathers with Pin" "30126.DAT" 0 1 0 0 0 1 0 0 0 1 0 3.83 17.76 -"Feathers with Pin and Black Tip Pattern" "30126p01.DAT" 0 1 0 0 0 1 0 0 0 1 0 3.83 17.76 -"Friends Glasses Heart Shaped with Pin" "96486.DAT" 0 1 0 0 0 1 0 0 0 1 0 -12 0 -"Friends Glasses Oval Shaped with Pin" "96490.DAT" 0 1 0 0 0 1 0 0 0 1 0 -12 0 -"Friends Hair Decoration Bow with Pin" "96479.DAT" 0 -1 0 0 0 1 0 0 0 -1 0 -12 0 -"Friends Hair Decoration Butterfly with Pin" "96481.DAT" 0 -1 0 0 0 1 0 0 0 -1 0 -12 0 -"Friends Hair Decoration, Bow w. Heart, Long Ribbon w. Pin" "11618.DAT" 0 -1 0 0 0 1 0 0 0 -1 0 -12 0 -"Friends Hair Decoration, Heart with Pin" "96485.DAT" 0 -1 0 0 0 1 0 0 0 -1 0 -12 0 -"Friends Hair Decoration, Star with Pin" "96489.DAT" 0 1 0 0 0 1 0 0 0 1 0 -12 0 -"Headphones / Ear Protection" "14045.DAT" 0 1 0 0 0 1 0 0 0 1 0 -11 0 -"Helmet Samurai Horn (repositioning may needed)" "529.DAT" 0 1 0 0 0 1 0 0 0 1 0 -6 -18 -"Helmet Visor" "2447.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Helmet Visor Ice Planet" "6119.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Helmet Visor Iron Man" "10908.DAT" 0 1 0 0 0 1 0 0 0 1 0 -8 -8 -"Helmet Visor Iron Man w. Gold Face, Blue Eyes Pattern" "10908P02.DAT" 0 1 0 0 0 1 0 0 0 1 0 -8 -8 -"Helmet Visor Iron Man w. Gold Face, White Eyes Pattern" "10908P01.DAT" 0 1 0 0 0 1 0 0 0 1 0 -8 -8 -"Helmet Visor Iron Man w. Silver Face, DkRed Line Pattern" "10908P04.DAT" 0 1 0 0 0 1 0 0 0 1 0 -8 -8 -"Helmet Visor Iron Man w. Silver Face, White Eyes Pattern" "10908P03.DAT" 0 1 0 0 0 1 0 0 0 1 0 -8 -8 -"Helmet Visor Space" "23318.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Helmet Visor Underwater" "6090.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Plume Dragon (repositioning may needed)" "87687.DAT" 0 1 0 0 0 1 0 0 0 1 0 -12 7 -"Plume Large (repositioning may needed)" "87694.DAT" 0 1 0 0 0 1 0 0 0 1 0 -12 7 -"Plume Small (repositioning may needed)" "87693.DAT" 0 1 0 0 0 1 0 0 0 1 0 -12 7 -"Plume Triple (repositioning may needed)" "87692.DAT" 0 1 0 0 0 1 0 0 0 1 0 -12 7 -"Plume/Flame Triple (repositioning may needed)" "64647.DAT" 0 1 0 0 0 1 0 0 0 1 0 -12 7 - - - -[HEAD] -"Stud Solid" "3626A.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Stud Solid with Standard Grin Pattern" "3626AP01.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Standard Grin Pattern" "3626BP01.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Adventurers Mummy Pattern" "3626BPA2.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Beard Stubble, Eyebrows, Smile, Scar Pattern" "3626CPQ0.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Beard, Happy/Angry Pattern (front)" "3626CPBB.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Beard, Happy/Angry Pattern (rear)" "3626CPBB.DAT" 0 -1 0 0 0 1 0 0 0 -1 0 0 0 -"Beard, Sneering/Scared Pattern (front)" "3626CPBH.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Beard, Sneering/Scared Pattern (rear)" "3626CPBH.DAT" 0 -1 0 0 0 1 0 0 0 -1 0 0 0 -"Black Eyebrows and Cheek Lines Pattern (front)" "3626CPB9.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Black Eyebrows and Cheek Lines Pattern (rear)" "3626CPB9.DAT" 0 -1 0 0 0 1 0 0 0 -1 0 0 0 -"Black Mask, Blue Eyes and Black Lips Pattern" "3626BPBA.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Black Moustache, Beard and Messy Hair Pattern" "3626BP44.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Blue Headband and Dark Orange Hair Pattern" "3626BP66.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Blue Sunglasses Pattern" "3626bp7b.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 - -; Update 2015-01 -"Blue Sunglasses and Stubble Pattern" "3626BP7E.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 - -"Blue Wrap-Around Sunglasses Pattern" "3626bp7c.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Big Eyes, Curved Eyebrows, Orange Mouth Pattern" "3626BPAO.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 - -; Update 2015-01 -"Brown Bushy Moustache, Eyebrows, Black Chin Strap Pattern" "3626CPCBE.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 - -"Brown Eyebrows, Smirking Face, Pupils Pattern" "3626BP83.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Brown Hair over Eye and Black Eyebrows Pattern" "3626BP7A.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Brown Hair, Eyelashes, and Lipstick Pattern" "3626BPA6.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Brown Moustache, Stubble, Eyebrows, Frowning Pattern" "3626BP3R.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Dark Grey Facial Hair Pattern" "3626BP39.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Dark Orange Moustache, Beard and Messy Hair Pattern" "3626BP42.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"DkRed Lips, Open/Closed Mouth, Freckles Pattern (front)" "3626CPBJ.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"DkRed Lips, Open/Closed Mouth, Freckles Pattern (rear)" "3626CPBJ.DAT" 0 -1 0 0 0 1 0 0 0 -1 0 0 0 -"DkRed Lips, Smirk/Eyemask Pattern (front)" "3626BPB8.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"DkRed Lips, Smirk/Eyemask Pattern (rear)" "3626BPB8.DAT" 0 -1 0 0 0 1 0 0 0 -1 0 0 0 -"Eye Patch, Black Stubble and Messy Hair Pattern" "3626BP49.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Eye Patch, DkOrange Moustache, Beard a. Messy Hair Pattern""3626BP46.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Eye Patch, DkOrange Stubble and Messy Hair Pattern" "3626BP48.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Eye Patch, Red Moustache, Beard and Messy Hair Pattern" "3626BP47.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Eyeglasses and Lightning Scar Pattern" "3626BPH1.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Eyes in Mask, White 'A' and Black Line on Back Pattern" "3626CPBL.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Evil Skeleton Skull Pattern" "3626BPA8.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 - -; Update 2015-01 -"Female with Lopsided Smile/Determined Pattern (front)" "3626CP8D.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Female with Lopsided Smile/Determined Pattern (rear)" "3626CP8D.DAT" 0 -1 0 0 0 1 0 0 0 -1 0 0 0 - -"Female with Brown Eyebrows, Pupils, Eyelashes Pattern" "3626BP09.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Female with Red Lips Small Eyebrows Pattern" "3626BP08.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Female with Smiling/Scared Pattern (front)" "3626BPQ3.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Female with Smiling/Scared Pattern (rear)" "3626BPQ3.DAT" 0 -1 0 0 0 1 0 0 0 -1 0 0 0 -"Freckle Nose and Standard Grin Pattern" "3626bp07.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Glasses and White Muttonchops Pattern" "3626BPA1.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Glasses, Brown Sideburns and Moustache Pattern" "3626BPQ4.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Glasses, Grey Eyes, Eyebrows, Cheeks Pattern" "3626CPBK.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Glasses, Thin Brown Eyebrows, Smile Pattern" "3626BP87.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Gold Paint and Slanted Eyes Pattern" "3626BP6U.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Gold Robot Pattern" "3626BP64.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Green Brain and Yellow Mouth Pattern" "3626BP6Y.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Green Lips and Red Eyebrows Pattern" "3626BPB5.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Gregory Goyle/Harry Potter Pattern (front)" "3626BPH4.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Gregory Goyle/Harry Potter Pattern (rear)" "3626BPH4.DAT" 0 -1 0 0 0 1 0 0 0 -1 0 0 0 -"Grey Hair, Beard, Moustache, Angry Pattern" "3626BP0A.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Grumpy/Angry Pattern (front)" "3626CPBD.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Grumpy/Angry Pattern (rear)" "3626CPBD.DAT" 0 -1 0 0 0 1 0 0 0 -1 0 0 0 -"Half-Moon Glasses and Grey Eyebrows Pattern" "3626BPHA.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Headset Over Brown Hair & Eyebrows Pattern" "3626BP69.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Ice Planet Female Red Hair Pattern" "3626BP65.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Ice Planet Messy White Hair Pattern" "3626BP62.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Ice Planet Moustache and Eyebrows Pattern" "3626BP61.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Islander White/Blue Painted Face Pattern" "3626BP3K.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Islander White/Red Painted Face Pattern" "3626BP3J.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Large Blue Mask Pattern" "3626BP6V.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Lefty Mouth and Stubble Pattern" "3626BP81.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"LOTR Brown Eyebrows Worried/Smile Pattern (front)" "3626CPM2.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"LOTR Brown Eyebrows Worried/Smile Pattern (rear)" "3626CPM2.DAT" 0 -1 0 0 0 1 0 0 0 -1 0 0 0 -"LOTR DkBrown Beard, Stubble and Stern Pattern (front)" "3626CPM7.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"LOTR DkBrown Beard, Clenched Teeth Pattern (rear)" "3626CPM7.DAT" 0 -1 0 0 0 1 0 0 0 -1 0 0 0 -"LOTR Frowning/Grimacing Pattern (front)" "3626CPM6.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"LOTR Frowning/Grimacing Pattern (rear)" "3626CPM6.DAT" 0 -1 0 0 0 1 0 0 0 -1 0 0 0 -"LOTR Frowning/Scared Pattern (front)" "3626CPM4.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"LOTR Frowning/Scared Pattern (rear)" "3626CPM4.DAT" 0 -1 0 0 0 1 0 0 0 -1 0 0 0 -"LOTR Frowning/Shouting Pattern (front)" "3626CPM5.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"LOTR Frowning/Shouting Pattern (rear)" "3626CPM5.DAT" 0 -1 0 0 0 1 0 0 0 -1 0 0 0 -"LOTR Orc with Grey Hair Pattern" "3626BPMA.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"LOTR Smirking/Shouting Pattern (front)" "3626CPM8.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"LOTR Smirking/Shouting Pattern (rear)" "3626CPM8.DAT" 0 -1 0 0 0 1 0 0 0 -1 0 0 0 -"LOTR Thick Gray Eyebrows and Smile Pattern" "3626CPM1.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"LOTR Tired/Poisoned Pattern (front)" "3626CPM3.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"LOTR Tired/Poisoned Pattern (rear)" "3626CPM3.DAT" 0 -1 0 0 0 1 0 0 0 -1 0 0 0 -"LOTR Uruk-Hai Lurtz Scowl and White Hand Pattern (front)" "3626BPMB.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"LOTR Uruk-Hai Lurtz Scowl and White Hand Pattern (rear)" "3626BPMB.DAT" 0 -1 0 0 0 1 0 0 0 -1 0 0 0 -"LOTR Uruk-Hai Scowl and White Hand Pattern (front)" "3626CPM0.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"LOTR Uruk-Hai Scowl and White Hand Pattern (rear)" "3626CPM0.DAT" 0 -1 0 0 0 1 0 0 0 -1 0 0 0 -"Mask Br.Green with Eyeholes and Smile Pattern" "3626BPB2.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Mask Purple with Eyeholes and Smile Pattern" "3626BPB6.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Messy Hair and Eye Patch Pattern" "3626BP31.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Messy Hair and Moustache Pattern" "3626BP30.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Messy Hair Female Pattern" "3626BP40.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Messy Hair, Beard and Eye Patch Pattern" "3626BP34.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Messy Hair, Moustache and Beard Pattern" "3626BP33.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Messy Hair, Moustache and Eye Patch Pattern" "3626BP32.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Messy Hair, Moustache and Stubble Pattern" "3626BP35.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Monocle and Black Slanted Eyebrows Pattern" "3626bpb7.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Monocle, Scar, and Moustache Pattern" "3626BPA7.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Mummy Face with 2 Eyes / 1 Eye Pattern (front)" "3626BPQ0.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Mummy Face with 2 Eyes / 1 Eye Pattern (rear)" "3626BPQ0.DAT" 0 -1 0 0 0 1 0 0 0 -1 0 0 0 -"Mummy with 2 Eyes / Gold Death Mask Pattern (front)" "3626BPQ1.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Mummy with 2 Eyes / Gold Death Mask Pattern (rear)" "3626BPQ1.DAT" 0 -1 0 0 0 1 0 0 0 -1 0 0 0 -"Open Smiling Mouth, Teeth and Tounge Pattern" "3626BPC44.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Orange Beard and White Smile Pattern" "3626BP80.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Peach Lips, Smile, Black Eyebrows Pattern" "3626BP8C.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Peach Lips, Smile, Black Eyebrows Pattern (Hollow Stud)" "3626CP8C.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Pursed Lips and White Forehead Pattern" "3626BPB1.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Red Lips and Black Upswept Eyelashes Pattern" "3626bp6f.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Red Moustache, Beard and Messy Hair Pattern" "3626BP43.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Ron Weasley Pattern" "3626bph3.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Severus Snape Pattern" "3626BPHB.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Sideburns and Droopy Moustache Black Pattern" "3626BP3N.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Sideburns and Droopy Moustache Brown Pattern" "3626BP3Q.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Sideburns, Goatee, Beard Stubble, Scar Pattern" "3626BPQ2.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Silver Mask and Mouth Grille Pattern" "3626BP6X.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Silver Robot Pattern" "3626BP63.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Silver Sunglasses and Red Headset Pattern" "3626BP68.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Skull Cracked with Metal Plates Pattern" "3626CPN2.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Skull Type 1 (Happy) Pattern" "82359.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Small Blue Mask Pattern" "3626BP6W.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Smile and Gold Tooth Pattern" "3626BP86.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Smile, Black Eyebrows and White Pupils Pattern" "3626BP84.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Smile, Brown Eyebrows and White Pupils Pattern" "3626BP85.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Smirk, Black Moustache Pattern" "3626BPA3.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Smirk, Black Hair and Goatee Pattern" "3626BP82.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Standard Grin and Eyebrows Pattern" "3626BP05.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Standard Grin and Pointed Moustache Pattern" "3626BP03.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Standard Grin and Sunglasses Pattern" "3626BP04.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Standard Grin, Eyebrows and Microphone Pattern" "3626BP06.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Standard Woman Pattern" "3626BP02.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Stubble, Moustache and Smirk Pattern" "3626BPA5.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"SW Alien with Large Black Eyes Pattern" "3626BPSB.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"SW Black Eyebrows and Scars Pattern" "3626BPS7.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"SW Brown Eyebrows and Beard Pattern" "3626BPS9.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"SW Brown Eyebrows Pattern" "3626BPS2.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"SW Darth Maul Pattern" "3626BPS8.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"SW Freckles and Thin Brown Eyebrows Pattern" "3626BPSD.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"SW Grey Beard and Eyebrows Pattern" "3626BPS4.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"SW Grey Eyebrows & Implant Pattern (front)" "3626BPSC.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"SW Grey Eyebrows & Implant Pattern (rear)" "3626BPSC.DAT" 0 -1 0 0 0 1 0 0 0 -1 0 0 0 -"SW Jawa, Yellow Eyes with Orange Rim Pattern" "3626CPS0.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"SW Red Lips, Black Eyes, Thin Eyebrows Pattern" "3626BPS0.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"SW Scout Trooper Black Visor Pattern" "3626BPSE.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"SW Small Black Eyebrows Pattern" "3626BPS3.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"SW Smirk and Brown Eyebrows Pattern" "3626BPS5.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"SW Tusken Raider Pattern" "3626BPST.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Tan Eyebrows and Frown Pattern" "3626BPH2.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Teeth, Pupils, Brown Eyebrows Pattern" "3626BP0B.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Thin Moustache, Stubble and Sideburns Pattern" "3626BP67.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Tribal Paint and Frown Pattern" "3626BPAC.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Uruk-Hai Scowl and White Hand Pattern (front)" "3626BPM0.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Uruk-Hai Scowl and White Hand Pattern (rear)" "3626BPM0.DAT" 0 -1 0 0 0 1 0 0 0 -1 0 0 0 -"Villian Black Facial Hair Pattern" "3626BPA4.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Villainous Glasses & Black Facial Hair Pattern" "3626bpa9.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Vincent Crabbe/Ron Weasley Pattern" "3626bph5.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"White Hair, Eyebrows, and Moustache Pattern" "3626BPN1.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Wide Smile, Red Lips and Crow's Feet Pattern" "3626BPB3.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Wiry Moustache, Goatee and Eyebrows Pattern" "3626bp3e.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"--------------------Non-standard heads------------------------------------------" "" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Alien Squidman" "85947.DAT" 0 1 0 0 0 1 0 0 0 1 0 24 0 -"Alien Squidman with Black Eyes & Lines Pattern" "85947P01.DAT" 0 1 0 0 0 1 0 0 0 1 0 24 0 -"Anubis Guard" "93248.DAT" 0 1 0 0 0 1 0 0 0 1 0 24 0 -"Anubis Guard with Gold Eye and Stripes Pattern" "93248PQ0.DAT" 0 1 0 0 0 1 0 0 0 1 0 24 0 -"Elf" "43745.DAT" 0 1 0 0 0 1 0 0 0 1 0 24 0 -"Elf with Green Eyes Pattern" "43745P01.DAT" 0 1 0 0 0 1 0 0 0 1 0 24 0 -"Ewok" "64805.DAT" 0 1 0 0 0 1 0 0 0 1 0 24 0 -"Goblin" "42109.DAT" 0 1 0 0 0 1 0 0 0 1 0 24 0 -"Martian Head with Clip" "30529.DAT" 0 1 0 0 0 1 0 0 0 1 0 32 0 -"Martian Head with Clip with Eyes Plain Pattern" "30529P01.DAT" 0 1 0 0 0 1 0 0 0 1 0 32 0 -"Martian Head with Clip with Eyelashes Pattern" "30529P02.DAT" 0 1 0 0 0 1 0 0 0 1 0 32 0 -"Mechanical Head SW Battle Droid" "30378.DAT" 0 1 0 0 0 1 0 0 0 1 0 32 0 -"Nautolan" "57901.DAT" 0 1 0 0 0 1 0 0 0 1 0 24 0 -"Nautolan, Black Eyes & Mouth, Brown Tentacle Bands" "57901P01.DAT" 0 1 0 0 0 1 0 0 0 1 0 24 0 -"Protocol Droid" "30480.DAT" 0 1 0 0 0 1 0 0 0 1 0 24 0 -"Protocol Droid with Light Yellow Eyes Pattern" "30480PS0.DAT" 0 1 0 0 0 1 0 0 0 1 0 24 0 -"Robot" "98384.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Robot with Blue Eyes and Red/yellow Teeth Display" "98384P01.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Rodian without Pattern" "47545.DAT" 0 1 0 0 0 1 0 0 0 1 0 24 0 -"Rodian with Eyes and Nose Pattern" "47545P01.DAT" 0 1 0 0 0 1 0 0 0 1 0 24 0 -"Simpsons Bart Simpson" "15523.DAT" 0 1 0 0 0 1 0 0 0 1 0 24 0 -"Simpsons Bart Simpson with Eyes Looking Left Pattern" "15523P01.DAT" 0 1 0 0 0 1 0 0 0 1 0 24 0 -"Simpsons Bart Simpson with Eyes Pattern" "15523P02.DAT" 0 1 0 0 0 1 0 0 0 1 0 24 0 -"Simpsons Homer Simpson" "15527.DAT" 0 1 0 0 0 1 0 0 0 1 0 24 0 -"Simpsons Homer Simpson with Half Closed Eyes Pattern" "15527P01.DAT" 0 1 0 0 0 1 0 0 0 1 0 24 0 -"Simpsons Homer Simpson with Wide Open Eyes Pattern" "15527P02.DAT" 0 1 0 0 0 1 0 0 0 1 0 24 0 -"Simpsons Lisa Simpson" "15524.DAT" 0 1 0 0 0 1 0 0 0 1 0 24 0 -"Simpsons Lisa Simpson with Eyes Pattern" "15524P02.DAT" 0 1 0 0 0 1 0 0 0 1 0 24 0 -"Simpsons Lisa Simpson with Worried Eyes Pattern" "15524P01.DAT" 0 1 0 0 0 1 0 0 0 1 0 24 0 -"Simpsons Marge Simpson" "15522.DAT" 0 1 0 0 0 1 0 0 0 1 0 24 0 -"Simpsons Marge Simpson with Eyes Looking Right Pattern" "15522P01.DAT" 0 1 0 0 0 1 0 0 0 1 0 24 0 -"Simpsons Marge Simpson with Wide Open Eyes Pattern" "15522P02.DAT" 0 1 0 0 0 1 0 0 0 1 0 24 0 - -; Update 2015-01 -"Simpsons Ned Flanders" "15529.DAT" 0 1 0 0 0 1 0 0 0 1 0 24 0 -"Simpsons Ned Flanders w. Glasses, Hair, Moustache Pattern" "15529P01.DAT" 0 1 0 0 0 1 0 0 0 1 0 24 0 - - -"SpongeBob" "54872.DAT" 0 1 0 0 0 1 0 0 0 1 0 8 0 -"SpongeBob with Happy Pattern" "54872p01.DAT" 0 1 0 0 0 1 0 0 0 1 0 8 0 -"SpongeBob with Shocked Pattern" "54872P02.DAT" 0 1 0 0 0 1 0 0 0 1 0 8 0 -"SpongeBob with Super Hero Pattern" "54872P09.DAT" 0 1 0 0 0 1 0 0 0 1 0 8 0 -"Spongebob Octopus" "64767.DAT" 0 1 0 0 0 1 0 0 0 1 0 24 0 -"Spongebob Starfish" "54873.DAT" 0 1 0 0 0 1 0 0 0 1 0 24 0 -"Stud Hollow" "3626B.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Wookiee with Bandolier" "30483.DAT" 0 1 0 0 0 1 0 0 0 1 0 24 0 -"Wookiee with Silver Bandolier/Black Nose Pattern" "30483P01.DAT" 0 1 0 0 0 1 0 0 0 1 0 24 0 -"Yoda with Curved Ears" "41880.DAT" 0 1 0 0 0 1 0 0 0 1 0 24 0 -"--------------------------------------------------------------------------------" "" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"None" "" 0 1 0 0 0 1 0 0 0 1 0 0 0 - - - -[BODY] -"Plain" "973.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"#1 Racing Pattern" "973P80.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"'S' Logo Grey / Blue Pattern" "973P23.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"'S' Logo Red / Black Pattern" "973P14.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"'Tine' Sticker" "973D01.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"2 Chinese Letters Yellow Stripe Pattern" "973PAQ.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"3-Piece Suit, White Shirt and Red Tie Pattern" "973PDB.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Air Gauge and Pocket Pattern" "973P29.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Airplane Logo and 'AIR' Badge Pattern" "973P85.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Airplane Logo Pattern" "973P16.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Anchor Motif Pattern" "973P09.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Arctic Parka 'A1' Pattern" "973P7A.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Arctic Parka 'A2' Pattern" "973P7B.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Armor Vest, Silver Wolf Head and Blue Round Jewel Pattern" "973PAW.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Astro Pattern" "973P6F.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Autoroute Pattern" "973P27.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Aviator Jacket w. Eagle/'SMH' on Back Pattern" "973PQ5.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Bandage and Gold Necklace Pattern" "973PQ0.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Bandage, Gold Necklace and Gold Belt Pattern" "973PQ1.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Batman Robin Pattern" "973Pb2.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Black Collar and Pockets Pattern" "973pst.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Black Diagonal Zip and Pocket Pattern" "973p0b.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Black Dungaree Pattern" "973P1A.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Black Falcon Pattern" "973P43.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Black Futuron Pattern" "973P6B.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Black Half Pattern" "973PBM.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Blacktron I Pattern" "973P52.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Blacktron II Pattern" "973P51.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Blouse, Belt and Necklace Pattern" "973PQ6.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Blue and Mint Green Stripes Pattern" "973p2e.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Blue Castle Bodice Pattern" "973P4N.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Blue Dungaree Pattern" "973P1B.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Blue Futuron Pattern" "973P6C.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Blue Flowers on Tied Shirt Pattern" "973P2G.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Blue Horizontal Stripes Pattern" "973p1d.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Blue Imperial Guard Officer Pattern" "973P3R.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Blue Imperial Guard Pattern" "973P3N.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Blue Plaid Shirt" "973PDD.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Blue Shirt and Safety Stripes Pattern" "973P8G.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Blue Striped Dungarees Pattern" "973P1R.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Blue Undershirt Green Bow and Gun Pattern" "973PW5.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Blue Vest, Collar and Star Pattern" "973PAR.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Blue Vest, Collar and Test Tube Pattern" "973PAS.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Blue Vest, Pockets, Shirt and Drill Pattern" "973PAT.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Blue Vest, Tools, Shirt and Bomb Pattern" "973PAU.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Bomber Jacket & Black Shirt Pattern" "973P70.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Bomber Jacket, Belt, & Black Shirt Pattern" "973PA5.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Brown Vest, Ascot and Belt Pattern" "973P3B.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Brown Vest, Buckle and String Bowtie Pattern" "973PW9.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 - -; Update 2015-01 -"Business Suit and Tie, Breathing Apparatus, Octan Pattern" "973P6H.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 - -"Buttons and Police Badge Plain Pattern" "973P1F.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Card, Suit, Vest, and Gold Fob Pattern" "973PW8.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Castle Breastplate Pattern" "973P40.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Castle Bodice and Cloak Pattern" "973P4H.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Castle Chainmail Pattern" "973P41.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Castle Crossed Pikes Pattern" "973P42.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Castle Female Armour Pattern" "973P4G.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Castle Red/Gray Pattern" "973P47.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Catsuit, Ring Zipper Pull and Belt Pattern" "973PB8.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Chef Pattern" "973p2a.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Classic Space Pattern" "973P90.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 - -; Update 2015-01 -"Classic Space Simulated Wear Pattern" "973P91.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 - -"Clockwork Robot Pattern" "973PC67.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Construction Safety Vest with Reflective Stripes Pattern" "973P8I.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Corset with Reddish Brown Laces Pattern" "973p4w.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Crew Neck Sweater with Bright Pink Collar Pattern" "973PD17.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Crew Neck Sweater w. Collar and 'HAIL TO THE CHEF'Pattern" "973P89.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Crown on DarkBlue/MediumBlue Quarters Pattern" "973p4j.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Dark Orange Vest and Purple Bow Tie Pattern" "973pb7.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"DkBlue Muscles and Gold Necklace Pattern" "973pq2.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"DkGreen Corset with Leather Belt Pattern" "973p4x.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"DkGray, Black, and Yellow Batman Pattern" "973PB1.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Dragon Head Pattern" "973P4B.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Dress and Red Beads Necklace Pattern" "973PD13.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Dress, White Apron and Red Beads Necklace" "973P88.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Explorien Logo Pattern" "973p55.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Extreme Team Jacket Logo Pattern" "973P8A.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Fantasy Era Peasant Rope Belt Pattern" "973p4v.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 - -; Update 2015-01 -"Female Jumpsuit w. Zipper, Markings, Classic Space Pattern""973P6G.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 - -"Female Pirate Pattern" "973P38.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Female Shirt with Two Buttons and Shell Pendant Pattern" "973P8K.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Female White Shirt, Open Jacket Pattern" "973PAE.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Female with Harlequin Black/White Pattern" "973PBA.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Female with Jacket, 2 Pockets, Buttons, Necklace Pattern" "973PBJ.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Female with LtPurple Scarf and Gray Belt Pattern" "973P7Y.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Five Button Fire Fighter Pattern" "973P21.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Forestman and Purse Pattern" "973P46.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Forestman Black Collar Pattern" "973P50.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Forestman Blue Collar Pattern" "973P49.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Forestman Maroon Collar Pattern" "973P48.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Four Button Suit and Train Logo Pattern" "973P84.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Front and Rear Stickers w. 'TINE' Logo on Blue Background" "973D05.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Gold Fob and 100 Dollar Bills Pattern" "973PWA.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Gold Ice Planet Pattern" "973P61.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Gold Lion and Belt on Red/White Quarter Pattern" "973P4L.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Gold Necklace and Yellow Undershirt Pattern" "973P72.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Grey and Gold Batman Pattern" "973pb0.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Grey Muscles and Arc Reactor Pattern" "973PBH.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Green Castle Bodice Pattern" "973P4Q.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Green Dungaree Pattern" "973P1J.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Green Stripes and Leather Strap Pattern" "973P3T.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Gryffindor Uniform Pattern" "973PH1.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Hogwarts Uniform Pattern" "973PH0.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Hooded Sweatshirt/Blue Pocket/Drawstring Pattern" "973p7j.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Horse Head Pattern" "973P2M.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"HP Jacket with 4 Button Vest and Bow Tie Pattern" "973PH4.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"HP with Dark Red Sweater and Yellow Neck Pattern" "973ph8.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"HP with Grey Sweater and Light Flesh Neck Pattern" "973ph7.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"HP with Jacket and Dark Red Sweater Pattern" "973ph6.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"HP with Jacket and Light Grey Sweater Pattern" "973ph5.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Imperial Soldier Pattern" "973P3U.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Insectoids Female, Blue Diamond under Circuits Pattern" "973P58.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Iron Man Armoured Suit Mark VI Pattern" "973PBB.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Iron Man Armoured Suit Mark VII Pattern" "973PBC.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Iron Man Armoured Suit Mark XLII Pattern" "973PBF.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Iron Man Armoured Suit Mark XVII Pattern" "973PBE.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Iron Patriot Armoured Suit Pattern" "973PBG.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Ivy Dress Pattern" "973PB5.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Jacket, Badge and Red Tie Pattern" "973P7R.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Jacket, Bow Tie, Vest, Boutonniere Pattern" "973PC23.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Jacket, Orange Vest, Green Neck-chief Pattern" "973PB3.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Jacket, Pink Shirt, Ring on Necklace Pattern" "973p7h.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Jacket, Pocket, Badge, Blue Tie Pattern" "973P7Q.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Jacket, Tie and Police Badge Yellow Star Pattern" "973p76.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Jacket, White Shirt, and Necklace Pattern" "973PA8.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Jacket over Lt Blue Button Down Shirt Pattern" "973P7Z.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Jacket over Shirt and Prison Stripes Pattern" "973p7t.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Jail Stripes and '23768' Pattern" "973P7K.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Launch Command Logo and Equipment Pattern" "973p1q.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Leather Jacket Pattern" "973P28.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Leather Jacket and Badge Pattern" "973P7U.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Leather Jacket, Badge, 'POLICE' Back Pattern" "973p7n.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Leather Jacket and Light Gray Shirt Pattern" "973PA9.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Lifebelt Logo and ID Card Pattern" "973P79.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Lion Gold on Blue Shield Pattern" "973P4F.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"LOTR Armor, Brown Belt & Gold Buckle Pattern" "973PM5.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"LOTR Button Shirt with Braces Pattern" "973PM2.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"LOTR Coat, DkBluish Grey Shirt, Evenstar Pendant Pattern" "973PM7.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"LOTR Cloak, Rope and Belt Pattern" "973PM1.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"LOTR Cloak with Dark Bluish Grey Folds Pattern" "973PM9.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"LOTR Jacket and Dark Red Vest Pattern" "973PM3.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"LOTR Jacket and Yellow Vest Pattern" "973PM8.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"LOTR Leather Armor with Buckle Pattern" "973PM0.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"LOTR Orc Leather Armor Pattern" "973PMA.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"LOTR Scale Armor and Belt Pattern" "973PM6.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"LOTR Shirt, Dark Brown Belt & Bag Pattern" "973PM4.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"LOTR Uruk-Hai Lurtz Muscles Outline Pattern" "973PMB.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Magenta Questionmark Pattern" "973PB6.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Mail Horn Pattern" "973P1S.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Maroon/Red Quarters Shield Pattern" "973P4U.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Mayan Necklace, Tribal Shirt, & Navel Pattern" "973PAC.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"MBA Level 1 Logo Pattern" "973PT0.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"MBA Level 2 Logo Pattern" "973PT1.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Medallion, Belt and Silver Buttons Pattern" "973p3d.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Modern Firefighter Type 1 Pattern" "973p77.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Modern Firefighter Type 2 Pattern" "973p78.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"MTron Logo Pattern" "973P68.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Necklace and Blue Squares Pattern" "973PWE.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Necklace and Fringe Pattern" "973PC11.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Neon Yellow Stripes, Radio and Badge Pattern" "973P7V.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Ninja Wrap, Gold Shuriken & Armour Pattern" "973PN6.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Ninja Wrap, Gold Shuriken & Dagger Pattern" "973PN7.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Ninja Wrap, Silver Shuriken & Dagger Pattern" "973PN5.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Octan OIL Badge Pattern" "973P81.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Octan Logo Pattern" "973PT2.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Old Obi-Wan Pattern" "973PS6.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 - -; Update 2015-01 -"Open Jacket, Blue Top and Navel Pattern" "973PD1.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 - -"Open Jacket over Striped Vest Pattern" "973P34.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Open Suit Revealing Superman Logo Pattern" "973PBK.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Palm Tree Pattern" "973P2H.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Palm Tree and Dolphin Pattern" "973P2J.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Palm Tree and Horse Pattern" "973P2K.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Patch Pocket Pattern" "973P26.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Pharaoh Breastplate Pattern" "973PA2.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Pinstriped Jacket and Gold Tie Pattern" "973P8L.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Pirate Captain Pattern" "973P36.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Pirate Green Vest, Shirt, and Belt Pattern" "973P3C.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Pirate Open Jacket over Brown Vest Pattern" "973P39.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Pirate Purple Vest and Anchor Tattoo Pattern" "973P30.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Pirate Ragged Shirt and Dagger Pattern" "973P3A.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Pirate Stripes Blue/White Pattern" "973P3E.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Pirate Stripes Blue/Cream Pattern" "973P32.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Pirate Stripes Red/Black Pattern" "973P33.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Pirate Stripes Red/Cream Pattern" "973P31.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Pirate Vest, Anchor Tattoo, Rope on Back Pattern" "973P3V.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Plain Shirt with Pockets Pattern" "973P7G.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Police Jacket, Silver Badge, 4 Buttons and Belt Pattern" "973PCBF.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Prisoner and '50380' Pattern" "973P7S.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Purple Greatcoat Pattern" "973phb.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Racing Jacket and Two Stars Pattern" "973P1H.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Racing Jacket and Two Stars Red Pattern" "973P1N.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Red Cross and Stethoscope Pattern" "973P25.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Red Cross Pattern" "973P24.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Red Dungaree Pattern" "973P1C.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Red Futuron Pattern" "973P6D.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Red Horizontal Stripes Pattern" "973p1E.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Red Imperial Guard Officer Pattern" "973P3S.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Red Imperial Guard Pattern" "973P3Q.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Red Necklace and Blue Undershirt Pattern" "973P71.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Red on Bottom and Fringe Pattern" "973pwd.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Red Shirt and Suit Pattern" "973P22.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Red Truck Pattern" "973P1T.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Red Undershirt and Fringe Pattern" "973PW7.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Red V-Neck and Buttons Pattern" "973P17.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Red Vest and Train Logo Pattern" "973P82.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Red & Gray Shirt, Pot Belly, Jacket Pattern" "973PAF.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Red/Peach Quarters Shield Pattern" "973P4T.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Red/White Waist, Zipper and White Star Pattern" "973pbl.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"RES-Q Orange Pockets and Logo Pattern" "973P8B.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Riding Jacket Pattern" "973P12.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Robot Pattern" "973P63.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Rock Raiders Jet Pattern" "973PAJ.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Royal Knights Lion Head & Neck-Chain Pattern" "973P4E.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Royal Knights Lion-Head Shield Pattern" "973P4D.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Rumpled Shirt, 2 Revolvers in Belt Pattern" "973PAA.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Safari Shirt, Black Tee, and Holster Pattern" "973PA7.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Safari Shirt, Blue Tee & Red Bandana Pattern" "973PA6.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Safari Shirt, Gun & Red Bandana Pattern" "973PA3.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Safari Shirt, Tan Bandana & Compass Pattern" "973PQ7.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Samurai Dragon Robe Pattern" "973PN0.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Samurai Robe, Sash and Dagger Pattern" "973PN1.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Security Guard Pattern" "973PB4.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Shell Logo Pattern" "973P60.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Sheriff Pattern" "973PW4.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Shirt Collar and Sand Green Neck Pattern" "973PX0.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Shirt with Black Belly Bump and Collar Outline Pattern" "973PD11.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Shirt, Badge, Blue Tie, 'POLICE' Back Pattern" "973P7M.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Shirt, Pink/Salmon Tie and ID Badge" "973P87.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Silver Armor Front and Back and Drill Pattern" "973PAV.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Silver Ice Planet Pattern" "973P62.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Six Button Suit and Airplane Pattern" "973p04.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Six Button Suit and Anchor Pattern" "973p05.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 - -; Update 2015-01 -"Skull and DkPink Roses Pattern" "973PC00.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Skull and Red Roses Pattern" "973PC44.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 - -"Slingshot on Back Pattern" "973PD12.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Slytherin Uniform Pattern" "973PH2.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Soccer Shirt '10' and 'ZIDANE' Pattern" "973PG0.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Space Police II and Radio Pattern" "973P69.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Space Police II Chief" "973P6A.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Spotted Singlet and Necklace Pattern" "973p2f.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Spyrius Pattern" "973P66.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Stethoscope and Pocket with Pens Pattern" "973P86.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Sticker Shell Logo on White Background" "973D04.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Straight Zipper Jacket Pattern" "973P13.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Strapless Suntop Pattern" "973P2C.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Striped Shirt and Silver Buttons Pattern" "973P3F.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Studded Armor Pattern" "973P45.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Studios Director Pattern" "973PD0.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Suit and Tie Pattern" "973P18.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Suit and Tie with Train Pattern" "973P83.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Suit with Pocket, Red Tie, Train Pattern" "973P8H.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Superman Logo and Dark Blue Muscles Pattern" "973pb9.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Suspenders and Red Bowtie Pattern" "973PA1.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"SW Belt Pockets and Necklace Blissl Flute Pattern" "973PRG.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"SW Black Vest & White Shirt Pattern" "973PS5.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"SW Blast Armor (Green Plates) Grey Pattern" "973PSB.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"SW Blast Armor (Green Plates) Bl.Grey Pattern" "973PRB.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"SW Blast Armor (Silver Plates) Pattern" "973PSJ.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"SW Blast Armor (Uncolored Plates) Pattern" "973PRC.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"SW Cad Bane Pattern" "973PSW.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"SW Camouflage Smock Pattern" "973PSM.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"SW Closed Shirt and Brown Belt Pattern" "973PR0.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"SW Dark Red Robe Pattern" "973PSX.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"SW Darth Vader Grey Pattern" "973PS7.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"SW Darth Vader Bluish Grey Pattern" "973PRA.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"SW Darth Vader Death Star Pattern" "973PSZ.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"SW Grey Shirt, Belt with Red Buckle Pattern" "973PR7.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"SW Gungan Dark Gray/Dark Tan Shirts Pattern" "973PR6.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"SW Hoth Trooper Pattern" "973PSH.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"SW Imperial Grand Moff Pattern" "973PR9.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"SW Imperial Officer Pattern" "973PSQ.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"SW Imperial Shuttle Pilot Pattern" "973PSN.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"SW Jawa Pattern" "973PSS.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"SW Jawa with Dark Brown Pouches and Black and Tan Straps" "973PRI.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"SW Jedi Robes and Sash Pattern" "973PS2.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"SW Layered Shirt, Brown Belt Pattern" "973PR3.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"SW Layered Shirt, Brown Belt, Braid Pattern" "973PR4.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"SW Layered Shirt, Waist Sash Pattern" "973PS8.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"SW Leia Hoth Jacket Pattern" "973PRD.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"SW Loose Dress Light Bluish Grey Folds Pattern" "973PSY.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"SW Loose Dress Light Grey Folds Pattern" "973PRY.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"SW Moisture Farmer Pattern" "973PSV.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"SW Nute Gunray Pattern" "973PRH.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"SW Pocket-Vest and Techno-Buckle Pattern" "973PSC.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"SW Protocol Droid Pattern" "973psr.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"SW Rebel A-Wing Pilot Pattern" "973PS0.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"SW Rebel Mechanic Pattern" "973PSA.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"SW Rebel Pilot Pattern" "973PS1.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"SW Rebel Pilot Bluish Grey Pattern" "973PR8.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"SW Robe and Rope Belt Pattern" "973PR2.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"SW Robe, Sash and Silver Neck Clasp Pattern" "973PR1.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 - -; Update 2015-01 -"SW Shadow Trooper Pattern" "973PRK.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 - -"SW Scout Trooper Pattern" "973PSE.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"SW Scout Trooper Bluish Grey Pattern" "973PRE.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"SW Shirt (Open Collar, No Vest) Pattern" "973PS4.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"SW Stormtrooper Pattern" "973PSK.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"SW Tank Top Pattern" "973PRF.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"SW Tunic and Belt Pattern" "973PSF.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"SW Vest, White Shirt & Lt Flesh Neck Pattern" "973PR5.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"SW Wrap-Around Tunic Pattern" "973PS3.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Tank Top, Braces & Yellow Skin Pattern" "973PQ4.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Tank Top, Stains, Wrench, and Tattoo Pattern" "973PAB.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Telephone Pattern" "973P8F.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Town Vest with Pockets and Striped Tie Pattern" "973P8J.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Train Chevron Pattern" "973P19.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Tri-Coloured Shield and Gold Trim Pattern" "973p4s.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Tri-Coloured Shield Large Pattern" "973P4R.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"TV Logo Pattern Large Pattern" "973p1m.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"TV Logo Pattern Small Pattern" "973P1K.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"UFO Alien Orange and Silver Pattern" "973P54.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"UFO Alien Triangular Insignia Pattern" "973P6U.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"UFO Alien Yellow Insignia, 3 Blue Bars Pattern" "973P6V.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"UFO Alien Circuitry, Red Level Pattern" "973P6W.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"UFO Silver and Gold Circuitry Pattern" "973P6X.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Unitron Pattern" "973P64.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"US Cavalry General Pattern" "973PW1.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"US Cavalry Officer Pattern" "973PW2.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"US Cavalry Soldier Pattern" "973PW3.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"V-Neck Shirt and Blue Overalls Pattern" "973P7W.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Vertical Red Stripes and 'Clutchers' Pattern" "973PC3G.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Vertical Striped Blue/Red Pattern" "973P02.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Vertical Striped Red/Blue Pattern" "973P01.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Vest with Patch Pockets Pattern" "973P73.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Vest, Patch Pockets and Police Badge Yellow Star Pattern" "973P74.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Vest, Slingshot in Belt Pattern" "973PAD.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Voldemort Robe Pattern" "973PH3.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Waistcoat, White Shirt and Bandolier Pattern" "973PQ3.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Waiter Pattern" "973P20.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"War Machine Armoured Suit Pattern" "973PBD.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"White/Blue Triangles, Blue/White Amulet Pattern" "973PWC.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"White/Blue Triangles, Red/White Amulet Pattern" "973PWB.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"White/Red Armour and White Belt" "973PWF.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"White Braces and Cartridge Belt Pattern" "973PW6.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"White Buttons and Police Badge Plain Sticker" "973D03.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"White Diagonal Zip and Pocket Pattern" "973p0a.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"White Envelope and Zipper Pattern" "973P7X.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"White Rope & Patched Collar Pattern" "973pdg.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"White Shirt and Jacket Pattern" "973P03.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"White Suit, Brown Vest and Tie Pattern" "973PA4.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Windsurfboard Pattern" "973P2D.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Wolfpack Pattern" "973P44.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Yellow Buttons and Grey Belt Sticker" "973D02.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Yellow Chest and White Beads Necklace Pattern" "973PD14.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Yellow Futuron Pattern" "973P6E.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Zipper and Police Badge Plain Pattern" "973P1G.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Zipper Jacket and 3 Pockets Pattern" "973P1U.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Zipper Jacket and Police Logo Pattern" "973P75.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"--------------------Non-standard torsi------------------------------------------" "" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Baby Body with Bodysuit" "15526.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Mechanical Head and Torso" "53988.DAT" 0 1 0 0 0 1 0 0 0 1 0 -8 0 -"Mechanical Torso" "30375.DAT" 0 1 0 0 0 1 0 0 0 1 0 40 0 -"Mechanical Torso with Blue Insignia" "30375PS3.DAT" 0 1 0 0 0 1 0 0 0 1 0 40 0 -"Mechanical Torso with Orange Insignia" "30375PS1.DAT" 0 1 0 0 0 1 0 0 0 1 0 40 0 -"Mechanical Torso with Tan Insignia" "30375PS2.DAT" 0 1 0 0 0 1 0 0 0 1 0 40 0 -"Mechanical Torso with 4 Side Attachment Cylinders" "54275.DAT" 0 1 0 0 0 1 0 0 0 1 0 10 0 -"Skeleton Torso" "6260.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Skeleton Torso with Shoulder Rods" "60115.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Torso with Integral Arms" "17.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"--------------------------------------------------------------------------------" "" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"None" "" 0 1 0 0 0 1 0 0 0 1 0 0 0 - - - -[BODY2] -"Plain" "3815.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 - -; Update 2015-01 -"Black Belt with Silver Belt Buckle Pattern" "3815P8I.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 - -"Clockwork Robot Pattern" "3815PC67.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Dark Grey Belt with Silver Buckle and Rivets Pattern" "3815PAW.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Gold Belt and DarkBlue Loincloth Pattern" "3815PQ0.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Gold Belt and Orange Cable Pattern" "3815P6U.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Gold O-Belt and Loincloth Pattern" "3815PQ2.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Gold X-Belt and Decorated Loincloth Pattern" "3815PQ1.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Harlequin Black Square Pattern" "3815PBA.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Holster and Belt Pattern" "3815PA9.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Iron Man Armoured Suit Mark XLII Pattern" "3815PBF.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Iron Man Armoured Suit Mark XVII Pattern" "3815PBE.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Iron Patriot Armoured Suit Pattern" "3815PBG.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Laboratory Smock Pattern" "3815PDE.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Leather Belt (Red Studs) Pattern" "3815p4f.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"LOTR Coat, Shirttails and Belt Pattern" "3815PM2.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"LOTR Dark Red Belt & Scale Armor Pattern" "3815PM1.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"LOTR Leather Armor" "3815PM0.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Purple Greatcoat Pattern" "3815phb.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Red/White Triangles Pattern" "3815PW1.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Robot Pattern" "3815p63.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Silver Belt Pattern" "3815P6W.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Silver Belt and Salmon Cable Pattern" "3815P6V.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Studded Belt Pattern" "3815PC44.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"SW Gunbelt Pattern" "3815ps5.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"SW Stormtrooper Pattern" "3815PSK.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"War Machine Armoured Suit Pattern" "3815PBD.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"White Apron Pattern" "3815P89.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 - -; Update 2015-01 -"White and Gold Markings Pattern" "3815P6G.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 - - -"--------------------Non-standard hips-------------------------------------------" "" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Hips and Legs Short with Hole" "41879B.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Hips and Legs Short without Hole" "41879A.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Hips and Legs Short with Horizontal Stripe" "16709.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Hips and Legs Short with Yellow Horizontal Stripe Pattern" "16709P01.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Hips and Legs Short w. Stripe, Slingshot on Back Pattern" "16709P02.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Legs Old" "15.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Martian Legs" "30530.DAT" 0 1 0 0 0 1 0 0 0 1 0 48 0 -"Mechanical Legs" "30376.DAT" 0 1 0 0 0 1 0 0 0 1 0 46 0 -"Slope Brick 65 2x2x2" "3678a.DAT" 0 -1 0 0 0 1 0 0 0 -1 0 0 0 -"Slope Brick 65 2x2x2 with DkGn Dress Pattern" "3678bp4x.DAT" 0 -1 0 0 0 1 0 0 0 -1 0 0 0 -"Slope Brick 65 2x2x2 with Queen's Dress Pattern" "3678ap4h.DAT" 0 -1 0 0 0 1 0 0 0 -1 0 0 0 -"Slope Brick 65 2x2x2 with White Apron Pattern" "3678bp4w.DAT" 0 -1 0 0 0 1 0 0 0 -1 0 0 0 -"Slope Brick 65 2x2x2 with Witch's Dress Pattern" "3678ap01.DAT" 0 -1 0 0 0 1 0 0 0 -1 0 0 0 -"--------------------------------------------------------------------------------" "" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"None" "" 0 1 0 0 0 1 0 0 0 1 0 0 0 - - - -[BODY3] -"None" "" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Armour SW Clone Trooper Tasset" "61190c.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Skirt 0.7L with 11 Diamond Points" "16820C01.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Skirt 1.1L with Straight Bottom" "600880C01.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Skirt 1.1L w. Straight Bottom w. Dark Green Apron Pattern" "600880P01C01.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Skirt 1.4L with Straight Bottom" "U9209C01.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Skirt 1.4L w. Straight Bottom w. White Apron Pattern" "U9209P01C01.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Skirt 1.5L Fringed" "14295C01.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Skirt 1.5L Fringed with Stepped Edge" "18200C01.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"--------------------------------------------------------------------------------" "" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"None" "" 0 1 0 0 0 1 0 0 0 1 0 0 0 - - - -[NECK] -"None" "" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"--------------------------------------------------------------------------------" "" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Armour Plate" "2587.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 - -; Update 2015-01 -"Armour Plate with LOTR King Theoden Pattern" "2587PM0.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 - -"Armour Samurai" "30174.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Armour Shoulder" "30121.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Armour Shoulder Pads w. 1 Stud on Front, 2 Studs on Back" "11097.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Armour SW Clone Trooper Pauldron" "61190b.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Armour SW Clone Trooper Tasset" "61190c.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Backpack Openable Closed" "30158c01.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Backpack Skydiver" "12897.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Bandana" "30133.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Bat Wing" "98722.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Beard Long Forked" "60750.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Beard Long with Five Braids" "60749.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Beard Short" "15501.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Beard with Rounded End" "10052.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Bracket 1 x 1 - 1 x 1" "42446.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Cape Cloth (Formed)" "50231C01.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Cape Cloth Floating (Formed)" "50231C02.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Cape Cloth Scalloped 5 Points (Formed)" "56630C01.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Cape Cloth Short (Formed)" "99464C01.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Cape Cloth with Holes and Tattered Edges (Formed)" "86038C01.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Cape Cloth with Inside Dark Red Pattern (Formed)" "50231P01C01.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Eagle Wing" "93250.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Minifig Eagle Wing with Tan Feathers and Red/Gold Pattern" "93250PQ0.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Epaulette" "2526.DAT" 0 1 0 0 0 1 0 0 0 1 0 -2 0 -"Airtanks" "3838.DAT" 0 1 0 0 0 1 0 0 0 1 0 -2 0 -"Arrow Quiver" "4498.DAT" 0 -1 0 0 0 1 0 0 0 -1 0 0 0 -"Backpack Non-Opening" "2524.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Cape" "4524.DAT" 0 1 0 0 0 1 0 0 0 1 0 -2 0 -"Container D-Basket" "4523.DAT" 0 1 0 0 0 1 0 0 0 1 0 1 0 -"Hair Beard" "6132.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Jet Pack with 2 Octagonal Nozzles" "6023.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Jet-Pack with Stud On Front" "4736.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Lifevest" "2610.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Sack" "92590.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Satchel (on right shoulder)" "61976.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Satchel (on left shoulder)" "61976.DAT" 0 -1 0 0 0 1 0 0 0 -1 0 0 0 -"Scabbard for Two Swords" "88290.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Scuba Tank" "30091.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Sword Scabbard (on right shoulder)" "95348.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Sword Scabbard (on left shoulder)" "95348.DAT" 0 -1 0 0 0 1 0 0 0 -1 0 0 0 -"Vest" "3840.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Vest with Crown on Dark Pink Sticker" "3840D01.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Vest with Crown on Violet Sticker" "3840D05.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Vest with Green Chevrons on Yellow Sticker" "3840D03.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Vest with Green Chevrons on Yellow.LtGrey Sticker" "3840D07.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Vest with White Maltese Cross on Red Sticker" "3840D02.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Vest with White Maltese Cross on Red/LtGrey Sticker" "3840D06.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Vest with Yellow Trefoils on Blue Sticker" "3840D04.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Vest with Yellow Trefoils on DkBlue Sticker" "3840D08.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 - - - -[LARM] -"Right" "3818.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Bionicle Arm Barraki" "57588.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Mechanical Arm" "30377.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Mechanical Arm Straight" "59230.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Mechanical Arm with Clip and Rod Hole" "53989.DAT" 0 0 0 1 0 1 0 -1 0 0 0 0 0 -"Mechanical Arm with Clip and Rod Hole" "76116.DAT" 0 0 0 1 0 1 0 -1 0 0 0 0 0 -"Short Sleeve and Yellow Arm Pattern" "3818P01.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Skeleton Arm" "6265.DAT" 0 1 0 0 0 1 0 0 0 1 -6 0 0.5 -"Wiry Bent with Clip" "10058.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 - -"--------------------------------------------------------------------------------" "" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"None" "" 0 1 0 0 0 1 0 0 0 1 0 0 0 - - - -[RARM] -"Left" "3819.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Bionicle Arm Barraki" "57588.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Mechanical Arm" "30377.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Mechanical Arm Straight" "59230.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Mechanical Arm with Clip and Rod Hole" "53989.DAT" 0 0 0 1 0 1 0 -1 0 0 0 0 0 -"Mechanical Arm with Clip and Rod Hole" "76116.DAT" 0 0 0 1 0 1 0 -1 0 0 0 0 0 -"Short Sleeve and Yellow Arm Pattern" "3819P01.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Skeleton Arm" "6265.DAT" 0 1 0 0 0 1 0 0 0 1 6 0 0.5 -"Wiry Bent with Clip" "10058.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 - -"--------------------------------------------------------------------------------" "" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"None" "" 0 1 0 0 0 1 0 0 0 1 0 0 0 - - - -[LHAND] -"Hand" "3820.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Hand Hook" "2531.DAT" 0 1 0 0 0 1 0 0 0 1 0 0.4 0 -"--------------------------------------------------------------------------------" "" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"None" "" 0 1 0 0 0 1 0 0 0 1 0 0 0 - - - -[RHAND] -"Hand" "3820.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Hand Hook" "2531.DAT" 0 -1 0 0 0 1 0 0 0 1 0 0.4 0 -"--------------------------------------------------------------------------------" "" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"None" "" 0 1 0 0 0 1 0 0 0 1 0 0 0 - - - -[LHANDA] -"None" "" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"--------------------------------------------------------------------------------" "" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Animal Snake" "30115.dat" 0 0.469472 0 -0.882948 0.882948 0 0.469472 0 -1 0 0 -4 -4 -"Animal Starfish" "33122.dat" 0 -1 0 0 0 0 1 0 1 0 0 -26 -6 -"Axe with Twin-Blade" "95052.DAT" 0 1 0 0 0 1 0 0 0 1 0 -1 0 -"Battleaxe" "3848.dat" 0 -1 0 0 0 1 0 0 0 -1 0 0 0 -"Bar 0.5L with Blade 3L" "64727.dat" 0 1 0 0 0 1 0 0 0 1 0 -8 0 -"Bar 0.5L with Curved Blade 2L" "87747.dat" 0 1 0 0 0 1 0 0 0 1 0 -8 0 -"Bar 0.5L with Faceted Spike 1L" "88695.dat" 0 1 0 0 0 1 0 0 0 1 0 -8 0 -"Bar 1.5L with Clip" "48729.dat" 0 1 0 0 0 1 0 0 0 1 0 -20 0 -"Bar 3L" "87994.dat" 0 1 0 0 0 1 0 0 0 1 0 -40 0 -"Bar 3L with White Ends Pattern" "87994p01.dat" 0 1 0 0 0 1 0 0 0 1 0 -40 0 -"Bar 4L Light Sabre Blade" "30374.dat" 0 1 0 0 0 -1 0 0 0 -1 0 12 0 -"Bar 4.5L Straight" "71184.dat" 0 1 0 0 0 1 0 0 0 1 0 20 0 -"Bar 4.5L with Handle" "87618.dat" 0 -1 0 0 0 -1 0 0 0 1 0 -80 0 -"Bar 6L with Thick Stop" "63965.dat" 0 1 0 0 0 1 0 0 0 1 0 -8 0 -"Bar 6.6L with Stop" "4095.dat" 0 1 0 0 0 1 0 0 0 1 0 -8 0 -"Barbed Wire Loop" "62700.dat" 0 0 -1 0 -1 0 0 0 0 -1 0 -2 0 -"Batarang" "55707c.dat" 0 0 1 0 -1 0 0 0 0 1 0 -2 0 -"Binoculars with Round Eyepiece" "30162.dat" 0 1 0 0 0 0 -1 0 1 0 -5 -1.6 0 -"Bone 2L" "93160.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Bone 5L" "92691.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Bottle Cylindrical" "95228.dat" 0 1 0 0 0 1 0 0 0 1 0 -12 0 -"Bottle Cylindrical with Bottle Ship Pattern" "95228p01.dat" 0 1 0 0 0 1 0 0 0 1 0 -12 0 -"Bow with Arrow" "4499.dat" 0 0 0 -1 0 1 0 1 0 0 0 1 0 - -; Update 2015-01 -"Brick 1 x 2 x 0.667 with 8 Studs and Angled Handle" "15071.DAT" 0 1 0 0 0 0.920505 0.390731 0 -0.390731 0.920505 0 -11 0 - -"Broom" "4332.dat" 0 -1 0 0 0 1 0 0 0 -1 0 -76 0 -"Bucket 1 x 1 x 1 Conical with Raised Handle" "95343C01.DAT" 0 0 -0.642788 -0.766044 1 0 0 0 -0.766044 0.642788 0 -1.5 0 -"Bucket 1 x 1 x 1 Cylindrical with Raised Handle" "12884C01.DAT" 0 0 -0.642788 -0.766044 1 0 0 0 -0.766044 0.642788 0 -1.5 0 -"Bugle" "71342.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Camera Movie" "30148.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Camera Snapshot" "30089.dat" 0 0 0.5 0.866025 0 0.866025 -0.5 -1 0 0 -4.062 2.5 -18 -"Camera with Side Sight" "4360.dat" 0 0 0 1 0 1 0 -1 0 0 0 -24 6.5 -"Castle Lance" "3849.dat" 0 1 0 0 0 0 1 0 -1 0 0 40 0 -"Chainsaw Blade" "6117.DAT" 0 1 0 0 0 0 -1 0 1 0 0 -11 -8 -"Cheerleader Pom Pom" "87997.DAT" 0 1 0 0 0 1 0 0 0 1 0 5 0 -"Cheerleader Pom Pom with Blue Pattern" "87997p01.DAT" 0 1 0 0 0 1 0 0 0 1 0 5 0 -"Cheerleader Pom Pom with Red Pattern" "87997p02.DAT" 0 1 0 0 0 1 0 0 0 1 0 5 0 -"Circular Blade Saw" "30194.dat" 0 -1 0 0 0 -0.422618 0.906308 0 0.906308 0.422618 0 15 -17 -"Coin with '1' Gothic Type" "96904.dat" 0 0 1 0 0 0 -1 -1 0 0 -2 -4 -10 -"Coin with '2' Gothic Type" "96905.dat" 0 0 1 0 0 0 -1 -1 0 0 -2 -4 -10 -"Coin with '5' Gothic Type" "96906.dat" 0 0 1 0 0 0 -1 -1 0 0 -2 -4 -10 -"Coin with '10' Gothic Type" "96907.dat" 0 0 1 0 0 0 -1 -1 0 0 -2 -4 -10 -"Coin with '10' Sans-serif Type" "70501a.dat" 0 0 1 0 0 0 -1 -1 0 0 -2 -4 -10 -"Coin with '20' Sans-serif Type" "70501b.dat" 0 0 1 0 0 0 -1 -1 0 0 -2 -4 -10 -"Coin with '30' Sans-serif Type" "70501c.dat" 0 0 1 0 0 0 -1 -1 0 0 -2 -4 -10 -"Coin with '40' Sans-serif Type" "70501d.dat" 0 0 1 0 0 0 -1 -1 0 0 -2 -4 -10 -"Comb" "30112b.dat" 0 1 0 0 0 1 0 0 0 1 0 -1 0 -"Compass" "889c01.dat" 0 1 0 0 0 1 0 0 0 1 0 -3 0 -"Conical Flask" "u9180.dat" 0 1 0 0 0 1 0 0 0 1 0 -10 0 -"Conical Flask TransClear with Coloured Base" "u9180c01.dat" 0 1 0 0 0 1 0 0 0 1 0 -10 0 -"Crossbow" "2570.dat" 0 1 0 0 0 1 0 0 0 1 0 -3 0 -"Cup" "3899.dat" 0 1 0 0 0 1 0 0 0 1 0 -15 -20 -"Dagger" "88288.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Dagger with Pearl Light Gray Blade" "88288P01.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Dinner Plate" "6256.dat" 0 0.0954045 -0.866025 -0.490814 0.981627 0 0.190809 -0.165245 -0.5 0.850114 7 -5 -26 -"Dynamite Sticks Bundle" "64728.dat" 0 0.5 0 0.866025 0 1 0 -0.866025 0 0.5 0 -28 -9 -"Electric Guitar" "93564.dat" 0 0 0 1 0 1 0 -1 0 0 0 4 0 -"Electric Guitar, Silver Strings, White Body" "93564P01.dat" 0 0 0 1 0 1 0 -1 0 0 0 4 0 -"Electric Guitar, Black Strings, DkPink Lightning" "93564P02.dat" 0 0 0 1 0 1 0 -1 0 0 0 4 0 -"Figure Club" "60659.dat" 0 1 0 0 0 1 0 0 0 1 0 3 0 -"Food Apple" "33051.dat" 0 0.857167 0.515038 0 -0.515038 0.857167 0 0 0 1 14 33 0 -"Food Banana" "33085.dat" 0 0 -1 0 1 0 0 0 0 1 0 0 0 -"Food Carrot" "33172.dat" 0 1 0 0 0 1 0 0 0 1 0 -50 0 -"Food Carrot Top" "33183.dat" 0 1 0 0 0 1 0 0 0 1 0 12 0 -"Food Carrot with Bright_Green Leaves" "33172c02.dat" 0 1 0 0 0 1 0 0 0 1 0 10 0 -"Food Carrot with Green Leaves" "33172c01.dat" 0 1 0 0 0 1 0 0 0 1 0 10 0 -"Food Cherry" "22667.dat" 0 1 0 0 0 1 0 0 0 1 0 -11 0 -"Food Croissant" "33125.dat" 0 0 1 0 -0.819152 0 0.573576 0.573576 0 0.819152 4 -27 -9 -"Food French Bread" "4342.dat" 0 0 -0.292372 0.956305 1 0 0 0 0.956305 0.292372 4.5 0 5 -"Food Ice Cream Cone" "33120.dat" 0 1 0 0 0 1 0 0 0 1 0 -2 0 -"Food Popsicle" "30222.dat" 0 1 0 0 0 1 0 0 0 1 0 -3 0 -"Food Sausage" "33078.dat" 0 0 -1 0 1 0 0 0 0 1 0 0 0 -"Food Turkey Leg" "33057.dat" 0 0 0.985 -0.174 0 0.174 0.985 1 0 0 9 -24 -1 -"Friends Access. Bag Round with Ruffle" "93090.DAT" 0 0 0 -1 1 0 0 0 -1 0 0 -1 -28 -"Friends Access. Bag Round w. Bright Pink Ruffle Pattern" "93090P01.DAT" 0 0 0 1 -1 0 0 0 -1 0 0 -1 -28 -"Friends Access. Bag Round w. Dark Pink Ruffle Pattern" "93090P02.DAT" 0 0 0 1 -1 0 0 0 -1 0 0 -1 -28 -"Friends Access. Bag Round w. Light Aqua Ruffle Pattern" "93090P03.DAT" 0 0 0 1 -1 0 0 0 -1 0 0 -1 -28 -"Friends Access. Basket" "93092.DAT" 0 1 0 0 0 0 1 0 -1 0 -15 -2 -29 -"Friends Access. Comb with Handle and 3 Hearts" "96482.DAT" 0 1 0 0 0 1 0 0 0 1 0 9 0 -"Friends Access. Cupcake Case" "97784.DAT" 0 1 0 0 0 1 0 0 0 1 0 -3 0 -"Friends Access. Cutlery Fork" "97781.DAT" 0 0 0 -1 0 1 0 1 0 0 0 -1 0 -"Friends Access. Cutlery Knife" "97782.DAT" 0 1 0 0 0 1 0 0 0 1 0 -1 0 -"Friends Access. Dish Rectangular" "97785.DAT" 0 1 0 0 0 1 0 0 0 1 0 -12 0 -"Friends Access. Dish Round 2.7 x 2.7" "97783.DAT" 0 1 0 0 0 1 0 0 0 1 0 -12 0 -"Friends Access. Frying Pan" "97790.DAT" 0 0 0 1 -1 0 0 0 -1 0 0 -56 -12 -"Friends Access. Hair Brush with Heart on Reverse" "96480.DAT" 0 0 0 -1 0 1 0 1 0 0 0 9 0 -"Friends Access. Hair Dryer" "96484.DAT" 0 1 0 0 0 1 0 0 0 1 0 8 0 -"Friends Access. Hand-held Food Mixer" "97793.DAT" 0 1 0 0 0 0 1 0 -1 0 0 -3 0 -"Friends Access. Lipstick with Light Bluish Grey Handle" "93094.DAT" 0 1 0 0 0 1 0 0 0 1 0 6 0 -"Friends Access. Mixing Bowl" "97791.DAT" 0 1 0 0 0 1 0 0 0 1 0 -12 0 -"Friends Access. Spatula with 3 Holes" "97787.DAT" 0 1 0 0 0 1 0 0 0 1 0 -1 0 -"Frypan" "4528.dat" 0 0 1 0 0 0 1 1 0 0 -4 -24 0 -"Goblet" "2343.dat" 0 1 0 0 0 1 0 0 0 1 0 -26 0 -"Goblet with Hollow Stem" "6269.dat" 0 1 0 0 0 1 0 0 0 1 0 -26 0 -"Gun Flintlock Pistol" "2562.dat" 0 1 0 0 0 1 0 0 0 1 0 -1 0 -"Gun Laser Kryptonian" "13952.DAT" 0 1 0 0 0 1 0 0 0 1 0 2 0 -"Gun Laser Pistol" "87993.dat" 0 1 0 0 0 1 0 0 0 1 0 -4 0 -"Gun Long Blaster" "57899.dat" 0 1 0 0 0 1 0 0 0 1 0 -20 0 -"Gun Musket" "2561.dat" 0 0 0.707 0.707 0 0.707 -0.707 -1 0 0 -25.1 -33.7 0 -"Gun Revolver" "30132.dat" 0 1 0 0 0 1 0 0 0 1 0 -3 0 -"Gun Rifle" "30141.dat" 0 0 0 1 0 1 0 -1 0 0 0 -8 0 -"Gun Semiautomatic Pistol" "55707a.dat" 0 1 0 0 0 1 0 0 0 1 0 -20 0 -"Gun Shooting Blaster with Dark Bluish Grey Trigger" "15391c01.DAT" 0 1 0 0 0 1 0 0 0 1 0 4 0 -"Gun Shooting Blaster with Trigger and TrOrange Projectile" "15391C02.DAT" 0 1 0 0 0 1 0 0 0 1 0 4 0 -"Gun SW Short Blaster" "58247.dat" 0 1 0 0 0 1 0 0 0 1 0 -3 0 -"Gun SW Small Blaster DC-17" "61190a.dat" 0 1 0 0 0 1 0 0 0 1 0 -3 0 -"Hairbrush" "3852.dat" 0 -1 0 0 0 1 0 0 0 -1 2.7 -8 0 -"Hand Fan" "93553.dat" 0 1 0 0 0 1 0 0 0 1 0 2 0 -"Hand Truck (Shortcut)" "2495c01.dat" 0 1 0 0 0 0 1 0 -1 0 22 -4 -58 -"Handcuffs" "61482.dat" 0 1 0 0 0 1 0 0 0 1 24 16 12 -"Harpoon" "57467.dat" 0 1 0 0 0 1 0 0 0 1 0 28 0 -"Hose Nozzle with Side String Hole" "58367.dat" 0 1 0 0 0 1 0 0 0 1 0 -2 0 -"Hose Nozzle with Side String Hole Simplified" "60849.dat" 0 1 0 0 0 1 0 0 0 1 0 -2 0 -"Ice Axe" "30193.dat" 0 1 0 0 0 1 0 0 0 1 0 6 0 -"Jackhammer" "30228.dat" 0 0.326 0 0.946 -0.899 -0.309 0.31 0.292 -0.951 0.101 2.5 -18.5 11 -"Key" "62808.DAT" 0 1 0 0 0 1 0 0 0 1 0 -2 0 -"Knife" "37.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Knife with Flat Hilt End" "95054.DAT" 0 1 0 0 0 1 0 0 0 1 0 -3 0 -"Ladle" "4337.dat" 0 1 0 0 0 1 0 0 0 1 0 -36 0 -"Life Ring" "30340.dat" 0 0 1 0 0 0 1 1 0 0 -4 16 -21 -"Lightning" "59233.dat" 0 1 0 0 0 1 0 0 0 1 0 -2 0 -"Lightsaber Chrome Silver - 1 Side On" "577Bc01.dat" 0 1 0 0 0 1 0 0 0 1 0 -20 0 -"Lightsaber Chrome Silver - 2 Sides On" "577Bc02.dat" 0 1 0 0 0 1 0 0 0 1 0 -20 0 -"Lightsaber Hilt with Bottom Ring" "577B.dat" 0 1 0 0 0 1 0 0 0 1 0 -20 0 -"Long Bow with Arrow" "93231.dat" 0 0.966 0 -0.259 0 1 0 0.259 0 0.966 0 -11 0 -"Loudhailer" "4349.dat" 0 1 0 0 0 1 0 0 0 1 0 -16 0 -"Loudhailer with Orange Stripe Pattern" "4349P01.DAT" 0 1 0 0 0 1 0 0 0 1 0 -16 0 -"Machine Gun with Drum Magazine" "55707b.dat" 0 1 0 0 0 1 0 0 0 1 0 -16 0 -"Magic Wand" "6124.dat" 0 1 0 0 0 1 0 0 0 1 0 8 0 -"Maracas" "90508.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Maracas with Green Border" "90508P01.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Medical Thermometer" "98393D.DAT" 0 0 0 1 0 1 0 -1 0 0 0 -26 -5 -"Metal Detector" "4479.dat" 0 1 0 0 0 1 0 0 0 1 0 -24 0 -"Microphone" "90370.dat" 0 1 0 0 0 1 0 0 0 1 0 -8 0 -"Microphone with Metallic Silver Top" "90370p01.dat" 0 1 0 0 0 1 0 0 0 1 0 -8 0 -"Mug" "33054.dat" 0 1 0 0 0 1 0 0 0 1 0 -12 -20 -"Pharaoh's Staff with Forked End" "93252.dat" 0 1 0 0 0 1 0 0 0 1 0 -42 0 -"Paint Brush" "93552.dat" 0 1 0 0 0 1 0 0 0 1 0 16 0 -"Paint Brush w. Silver Ring, Green Tip" "93552P01.dat" 0 1 0 0 0 1 0 0 0 1 0 16 0 -"Paint Palette" "93551.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Paint Palette with Paint Drops Pattern" "93551P01.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Paint Roller Brush Handle" "12885.DAT" 0 1 0 0 0 1 0 0 0 1 0 8 0 -"Pike / Spear Elaborate with Metallic Silver Head" "90391P01.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Pike / Spear Elaborate with Flat Silver Head" "90391P02.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Pipe Wrench" "4328.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Pitchfork" "4496.dat" 0 1 0 0 0 1 0 0 0 1 0 -12 0 -"Plant Flower Stem w. Bar w. 3 Flowers" "99249C01.DAT" 0 1 0 0 0 1 0 0 0 1 0 6 0 -"Plant Flower Stem w. Bar w. 3 Flowers w. 6 Rounded Petals" "99249C03.DAT" 0 1 0 0 0 1 0 0 0 1 0 6 0 -"Plant Flower Stem w. Bar w. 3 Roses" "99249C02.DAT" 0 1 0 0 0 1 0 0 0 1 0 6 0 -"Plunger" "11459.DAT" 0 1 0 0 0 -1 0 0 0 -1 0 -20 0 -"Plunger with Medium Dark Flesh Handle" "11459P01.DAT" 0 1 0 0 0 -1 0 0 0 -1 0 -20 0 -"Polearm Halberd" "6123.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Pushbroom" "3836.dat" 0 0 0 -1 0 -1 0 -1 0 0 0 44 0 -"Radio with Long Handle" "3962b.dat" 0 0 0 -1 0 1 0 1 0 0 0 -1 0 -"Radio with Short Handle" "3962a.dat" 0 0 0 -1 0 1 0 1 0 0 0 -1 0 -"Ring 1 x 1" "11010.dat" 0 0 -1 0 -1 0 0 0 0 -1 -4 -2 -6 -"Ring with Triangle" "87748.dat" 0 0 1 0 -0.866 0 0.5 0.5 0 0.866 0 -2 -25 -"Ring with Triangle with Gold Bands and Crab Pattern" "87748P01.dat" 0 0 1 0 -0.866 0 0.5 0.5 0 0.866 0 -2 -25 -"Ring with Triangle with Gold Bands and Manta Ray Pattern" "87748P05.dat" 0 0 1 0 -0.866 0 0.5 0.5 0 0.866 0 -2 -25 -"Ring with Triangle with Gold Bands and Shark Pattern" "87748P03.dat" 0 0 1 0 -0.866 0 0.5 0.5 0 0.866 0 -2 -25 -"Ring with Triangle with Gold Bands and Squid Pattern" "87748P04.dat" 0 0 1 0 -0.866 0 0.5 0.5 0 0.866 0 -2 -25 -"Ring with Triangle with Gold Bands and Triangle Pattern" "87748P06.dat" 0 0 1 0 -0.866 0 0.5 0.5 0 0.866 0 -2 -25 -"Ring with Triangle with Gold Bands and Turtle Pattern" "87748p02.dat" 0 0 1 0 -0.866 0 0.5 0.5 0 0.866 0 -2 -25 -"Rock 1 x 1 Gem Facetted" "30153.dat" 0 1 0 0 0 1 0 0 0 1 0 -8 0 -"Saucepan" "4529.dat" 0 0 1 0 0 0 1 1 0 0 -6 -24 0 -"Saxophone" "13808.DAT" 0 1 0 0 0 1 0 0 0 1 0 7 0 -"Saxophone with Black Mouthpiece" "13808P01.DAT" 0 1 0 0 0 1 0 0 0 1 0 7 0 -"Sextant" "30154.dat" 0 0 0 1 0 1 0 -1 0 0 0 -35 0 -"Shield Broad with Spiked Bottom and Cutout Corner" "10049.dat" 0 0 0 1 -1 0 0 0 -1 0 -4 -1 0 -"Shield Broad w. Spiked Bottom, Cutout Corner, Hand Pattern" "10049P01.dat" 0 0 0 1 -1 0 0 0 -1 0 -4 -1 0 -"Shield Octagonal with Stud" "48494.dat" 0 0 0 1 -1 0 0 0 -1 0 0 -2 0 -"Shield Octagonal without Stud" "61856.dat" 0 0 0 1 -1 0 0 0 -1 0 0 -2 0 -"Shield Octagonal with Troll Skull on Dark Red Pattern" "61856P40.dat" 0 0 0 1 -1 0 0 0 -1 0 0 -2 0 -"Shield Oval" "92747.dat" 0 0 0 1 -1 0 0 0 -1 0 -4 -1 0 -"Shield Oval with SW Gungan Patrol Shield" "92747p01.dat" 0 0 0 1 -1 0 0 0 -1 0 -4 -1 0 -"Shield Ovoid" "2586.dat" 0 0 0 1 -1 0 0 0 -1 0 -4 -1 0 -"Shield Ovoid with American Indian Pattern" "2586PW1.dat" 0 0 0 1 -1 0 0 0 -1 0 -4 -1 0 -"Shield Ovoid with Bat Pattern" "2586P4F.dat" 0 0 0 1 -1 0 0 0 -1 0 -4 -1 0 -"Shield Ovoid with Blue Dragon Pattern" "2586P4C.dat" 0 0 0 1 -1 0 0 0 -1 0 -4 -1 0 -"Shield Ovoid with Bull Head Pattern" "2586P4G.DAT" 0 0 0 1 -1 0 0 0 -1 0 -4 -1 0 - -; Update 2015-01 -"Shield Ovoid with Bull Head on Brown Border Sticker" "2586D01.DAT" 0 0 0 1 -1 0 0 0 -1 0 -4 -1 0 - -"Shield Ovoid with Crown on Dark/Med Blue Quarters Pattern" "2586P4J.DAT" 0 0 0 1 -1 0 0 0 -1 0 -4 -1 0 -"Shield Ovoid with DkGreen Dragon on MdDkFlesh/Tan Pattern" "2586P4K.DAT" 0 0 0 1 -1 0 0 0 -1 0 -4 -1 0 -"Shield Ovoid with Golden Lion Pattern" "2586PH1.DAT" 0 0 0 1 -1 0 0 0 -1 0 -4 -1 0 -"Shield Ovoid with Gold Lion on Red/White Quarters Pattern" "2586P4L.DAT" 0 0 0 1 -1 0 0 0 -1 0 -4 -1 0 -"Shield Ovoid with Green Dragon Pattern" "2586P4B.dat" 0 0 0 1 -1 0 0 0 -1 0 -4 -1 0 -"Shield Ovoid with Indigo Islanders Pattern" "2586P30.dat" 0 0 0 1 -1 0 0 0 -1 0 -4 -1 0 -"Shield Ovoid with Royal Knights Lion Pattern" "2586P4D.dat" 0 0 0 1 -1 0 0 0 -1 0 -4 -1 0 -"Shield Ovoid with Silver Skull on Dark Red Pattern" "2586P4H.DAT" 0 0 0 1 -1 0 0 0 -1 0 -4 -1 0 -"Shield Ovoid with Silver Snake Pattern" "2586PH2.DAT" 0 0 0 1 -1 0 0 0 -1 0 -4 -1 0 -"Shield Ovoid with SW Gungan Patrol Pattern" "2586PS1.DAT" 0 0 0 1 -1 0 0 0 -1 0 -4 -1 0 -"Shield Rectangular Curved with Stud" "98367.DAT" 0 0 0 -1 1 0 0 0 -1 0 0 -1 0 -"Shield Round" "3876.dat" 0 0 0 1 0 1 0 -1 0 0 0 -12 0 -"Shield Round Bowed" "75902.dat" 0 0 0 1 -1 0 0 0 -1 0 -4 -1 0 -"Shield Round Bowed with Bullseye with Star Pattern" "75902P02.dat" 0 0 0 1 -1 0 0 0 -1 0 -4 -1 0 -"Shield Round Bowed with DkGreen and Gold Rohan" "75902P01.dat" 0 0 0 1 -1 0 0 0 -1 0 -4 -1 0 -"Shield Round Bowed with Gold Eagle Pattern" "75902P03.DAT" 0 0 0 1 -1 0 0 0 -1 0 -4 -1 0 -"Shield Round Bowed with Mercedes-Benz Logo" "75902P04.DAT" 0 0 0 1 -1 0 0 0 -1 0 -4 -1 0 -"Shield Round Flat" "59231.dat" 0 0 0 1 0 1 0 -1 0 0 -10 -12 0 -"Shield Round Flat with Silver Skull on Dark Red Pattern" "59231P4H.dat" 0 0 0 1 0 1 0 -1 0 0 -10 -12 0 -"Shield Round Type 2" "91884.DAT" 0 0 0 1 1 0 0 0 1 0 -4 -2 0 -"Shield Round Type 2 w. Aztec Bird on Dark Red Pattern" "91884P04.DAT" 0 0 0 1 1 0 0 0 1 0 -4 -2 0 -"Shield Round Type 2 w. DkBrown Ring and 4 Rivets Pattern" "91884P01.DAT" 0 0 0 1 1 0 0 0 1 0 -4 -2 0 -"Shield Round Type 2 w. Dragon Heads and Ornaments Pattern" "91884P03.DAT" 0 0 0 1 1 0 0 0 1 0 -4 -2 0 -"Shield Round Type 2 w. Silver Rivets Pattern" "91884P02.DAT" 0 0 0 1 1 0 0 0 1 0 -4 -2 0 -"Shield Scarab" "93251.dat" 0 0 0 1 -1 0 0 0 -1 0 -9 -1 -1 -"Shield Triangular" "3846.dat" 0 0 0 1 0 1 0 -1 0 0 0 -12 0 -"Shield Triangular with Bat Pattern" "3846p4f.dat" 0 0 0 1 0 1 0 -1 0 0 0 -12 0 -"Shield Triangular with Black Falcon Blue Border Pattern" "3846p45.dat" 0 0 0 1 0 1 0 -1 0 0 0 -12 0 -"Shield Triangular with Black Falcon Yellow Border Pattern" "3846p46.dat" 0 0 0 1 0 1 0 -1 0 0 0 -12 0 -"Shield Triangular with Blue Dragon Pattern" "3846p4c.dat" 0 0 0 1 0 1 0 -1 0 0 0 -12 0 -"Shield Triangular with Blue Lion on Yellow Background" "3846p4g.dat" 0 0 0 1 0 1 0 -1 0 0 0 -12 0 -"Shield Triangular with Crown on Dark/Med Blue Quarters" "3846P4J.dat" 0 0 0 1 0 1 0 -1 0 0 0 -12 0 -"Shield Triangular with Crown on Dark-Pink Sticker" "3846d01.dat" 0 0 0 1 0 1 0 -1 0 0 0 -12 0 -"Shield Triangular with Crown on Violet Sticker" "3846d05.dat" 0 0 0 1 0 1 0 -1 0 0 0 -12 0 -"Shield Triangular with Dragon on MdDkFlesh/Tan Pattern" "3846P4K.dat" 0 0 0 1 0 1 0 -1 0 0 0 -12 0 -"Shield Triangular with Forestman Pattern" "3846p48.dat" 0 0 0 1 0 1 0 -1 0 0 0 -12 0 -"Shield Triangular w. Gold Lion on Red/White Quart. Patt." "3846P4L.dat" 0 0 0 1 0 1 0 -1 0 0 0 -12 0 -"Shield Triangular with Green Chevrons on Yellow Sticker" "3846d03.dat" 0 0 0 1 0 1 0 -1 0 0 0 -12 0 -"Shield Triangular with Green Chevrons on Yellow.LtGray" "3846d06.dat" 0 0 0 1 0 1 0 -1 0 0 0 -12 0 -"Shield Triangular with Lion Head, Blue & Yellow Pattern" "3846p4e.dat" 0 0 0 1 0 1 0 -1 0 0 0 -12 0 -"Shield Triangular with Maroon/Red Quarters Pattern" "3846p4u.dat" 0 0 0 1 0 1 0 -1 0 0 0 -12 0 -"Shield Triangular with Red and Gray Pattern, Blue Frame" "3846p47.dat" 0 0 0 1 0 1 0 -1 0 0 0 -12 0 -"Shield Triangular with Red Cross and Helmet" "3846p01.dat" 0 0 0 1 0 1 0 -1 0 0 0 -12 0 -"Shield Triangular with Red/Peach Quarters Pattern" "3846p4t.dat" 0 0 0 1 0 1 0 -1 0 0 0 -12 0 -"Shield Triangular with Royal Knights Lion Pattern" "3846p4d.dat" 0 0 0 1 0 1 0 -1 0 0 0 -12 0 -"Shield Triangular with White Maltese Cross on Red Sticker" "3846d02.dat" 0 0 0 1 0 1 0 -1 0 0 0 -12 0 -"Shield Triangular with Wolfpack Pattern" "3846p44.dat" 0 0 0 1 0 1 0 -1 0 0 0 -12 0 -"Shield Triangular with Yellow Lion on Blue Background" "3846p4h.dat" 0 0 0 1 0 1 0 -1 0 0 0 -12 0 -"Shield Triangular with Yellow Trefoils on Blue Sticker" "3846d04.dat" 0 0 0 1 0 1 0 -1 0 0 0 -12 0 -"Shield Triangular with Yellow Trefoils on DkBlue Sticker" "3846d07.dat" 0 0 0 1 0 1 0 -1 0 0 0 -12 0 -"Shovel" "3837.dat" 0 1 0 0 0 1 0 0 0 1 0 -12 0 -"Signal Holder" "3900.dat" 0 1 0 0 0 0 -1 0 1 0 0 -36 -2 -"Signal Holder with Black 'POLICE' and Red Line Pattern" "3900P01.DAT" 0 1 0 0 0 0 -1 0 1 0 0 -36 -2 -"Signal Holder with Green Circle on White Sticker" "3900d01.dat" 0 1 0 0 0 0 -1 0 1 0 0 -36 -2 -"Ski Pole" "90540.dat" 0 1 0 0 0 1 0 0 0 1 0 -8 0 -"Sledgehammer" "75904.dat" 0 0 0 1 0 1 0 -1 0 0 0 -14 0 -"Small Bow with Arrow" "95051.DAT" 0 0 0 1 0 1 0 -1 0 0 0 -10 0 -"Space Scanner Tool" "30035.dat" 0 1 0 0 0 1 0 0 0 1 0 -19 -10 -"Spear" "4497.dat" 0 1 0 0 0 1 0 0 0 1 0 -40 0 -"Spear with Four Side Blades" "43899.dat" 0 1 0 0 0 1 0 0 0 1 0 -144 0 -"Speargun" "30088.dat" 0 1 0 0 0 1 0 0 0 1 0 -13 0 -"Staff with Crescent End" "95050.DAT" 0 1 0 0 0 1 0 0 0 1 0 -1 0 -"Staff with Spherical End" "95049.DAT" 0 1 0 0 0 1 0 0 0 1 0 -1 0 -"Statuette" "90398.dat" 0 1 0 0 0 1 0 0 0 1 0 -1 0 -"Steak on Bone" "98372.dat" 0 1 0 0 0 1 0 0 0 1 0 -2 0 -"Steak on Bone with Red Meat" "98372P01.dat" 0 1 0 0 0 1 0 0 0 1 0 -2 0 -"Stretcher with Bottom Hinges" "4714.DAT" 0 0 0 -1 1 0 0 0 -1 0 26 -74 -2 -"Stretcher without Bottom Hinges" "93140.DAT" 0 0 0 -1 1 0 0 0 -1 0 26 -74 -2 -"Suitcase" "4449.dat" 0 0 0 -1 1 0 0 0 -1 0 0 0 0 -"Sword Cutlass" "2530.dat" 0 1 0 0 0 1 0 0 0 1 0 -2 0 -"Sword Greatsword" "59.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Sword Katana Type 1 (Octogonal Guard)" "30173a.dat" 0 1 0 0 0 1 0 0 0 1 0 6 0 -"Sword Katana Type 2 (Square Guard)" "30173b.dat" 0 1 0 0 0 1 0 0 0 1 0 6 0 -"Sword Khopesh" "93247.dat" 0 1 0 0 0 1 0 0 0 1 0 -8 0 -"Sword Longsword" "98370.dat" 0 1 0 0 0 1 0 0 0 1 0 -8 0 -"Sword Rapier" "93550.dat" 0 1 0 0 0 1 0 0 0 1 0 -2 0 -"Sword Roman Gladius" "95673.dat" 0 1 0 0 0 1 0 0 0 1 0 -8 0 -"Sword Saber with Clip Pommel" "59229.dat" 0 1 0 0 0 1 0 0 0 1 0 -2 0 -"Sword Scimitar" "43887.dat" 0 1 0 0 0 1 0 0 0 1 0 -18 0 -"Sword Scimitar with Jagged Edge" "60752.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Sword Shortsword" "3847.dat" 0 1 0 0 0 1 0 0 0 1 0 -12 0 -"Sword Small with Angular Guard" "95053.DAT" 0 1 0 0 0 1 0 0 0 1 0 -3 0 -"Sword Small with Curved Blade" "10053.DAT" 0 1 0 0 0 1 0 0 0 1 0 -2 0 -"Sword Uruk-Hai" "10050.dat" 0 -1 0 0 0 1 0 0 0 -1 0 4 0 -"Sword Sword with Angular Hilt" "48495.dat" 0 0 0 -1 0 1 0 1 0 0 0 -10 0 -"Syringe" "87989.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Telescope" "64644.dat" 0 1 0 0 0 1 0 0 0 1 0 -11 0 -"Tennis Racket" "93216.dat" 0 1 0 0 0 1 0 0 0 1 0 -3 0 -"Tomahawk with Flat-Silver Blade" "13571.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Tool 4-Way Lug Wrench" "604553.DAT" 0 1 0 0 0 1 0 0 0 1 0 -12 0 -"Tool Adjustable Wrench with 3-Rib Handle" "604614.DAT" 0 1 0 0 0 1 0 0 0 1 0 -2 0 -"Tool Battery Powered Drill" "604549.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Tool Binoculars Space" "30304.dat" 0 1 0 0 0 0 -1 0 1 0 -5 -1 0 -"Tool Box Wrench" "55300.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Tool Box Wrench with 3-Rib Handle" "604552.DAT" 0 1 0 0 0 1 0 0 0 1 0 -2 0 - -; Update 2015-01 -"Tool Crowbar" "92585.DAT" 0 1 0 0 0 1 0 0 0 1 0 -30 0 - -"Tool Fishing Rod" "2614.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Tool Grappling Hook" "30192.dat" 0 1 0 0 0 -1 0 0 0 -1 0 9 0 -"Tool Hammer" "55295.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Tool Hammer with 3-Rib Handle" "604547.DAT" 0 1 0 0 0 1 0 0 0 1 0 -2 0 -"Tool Handaxe" "3835.dat" 0 1 0 0 0 1 0 0 0 1 0 -16 0 -"Tool Hose Nozzle with Handle" "4210a.dat" 0 -1 0 0 0 1 0 0 0 -1 0 -12 0 -"Tool Magnifying Glass" "30152.dat" 0 1 0 0 0 1 0 0 0 1 0 -52 0 -"Tool Mallet" "4522.dat" 0 0 0 1 0 1 0 -1 0 0 0 -28 0 -"Tool Oar" "2542.dat" 0 -1 0 0 0 -1 0 0 0 1 0 40 0 -"Tool Oilcan" "55296.DAT" 0 1 0 0 0 1 0 0 0 1 0 -6 0 -"Tool Oilcan with Ribbed Handle" "604548.DAT" 0 1 0 0 0 1 0 0 0 1 0 -3 0 -"Tool Open End Wrench" "55299.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Tool Open End Wrench with 3-Rib Handle" "604551.DAT" 0 1 0 0 0 1 0 0 0 1 0 -2 0 -"Tool Pickaxe" "3841.dat" 0 1 0 0 0 1 0 0 0 1 0 -12 0 -"Tool Power Drill" "55297.dat" 0 1 0 0 0 1 0 0 0 1 0 -6 0 -"Tool Screwdriver" "55298.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Tool Screwdriver with Wide Head and 3-Rib Handle" "604550.DAT" 0 1 0 0 0 1 0 0 0 1 0 -2 0 -"Tool Socket Wrench with Ratchet and 3-Rib Handle" "604615.DAT" 0 1 0 0 0 1 0 0 0 1 0 -2 0 -"Tool Spanner/Screwdriver" "4006.dat" 0 0 0 -1 0 1 0 1 0 0 0 -14 0 -"Toolbox 1 x 3 with Handle" "98368.dat" 0 0 0 1 -1 0 0 0 -1 0 0 -2 0 -"Torch" "3959.dat" 0 1 0 0 0 1 0 0 0 1 0 -13 0 -"Torch without Grooves" "86208.dat" 0 1 0 0 0 1 0 0 0 1 0 -13 0 -"Toy Winder Key" "98375.dat" 0 0 0 -1 1 0 0 0 -1 0 0 -2 -20 -"Tray Oval" "11252.dat" 0 0 -1 0 1 0 0 0 0 1 -6 -3 -16 -"Underwater Scooter" "30092.dat" 0 -1 0 0 0 1 0 0 0 -1 20 -22 -8.5 -"Weapon Billy Club" "13790.DAT" 0 1 0 0 0 1 0 0 0 1 0 -7.5 0 -"Weapon Bladed Claw" "88811.dat" 0 1 0 0 0 1 0 0 0 1 0 2 0 -"Weapon Club with Spikes" "88001.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Weapon Crescent Blade Serrated with Bar 0.5L" "98141.dat" 0 1 0 0 0 1 0 0 0 1 0 2 0 -"Weapon Curved Blade 8.5L with Bar 1.5L" "98137.dat" 0 1 0 0 0 1 0 0 0 1 0 12 0 -"Weapon Hand Dagger" "88812.dat" 0 1 0 0 0 1 0 0 0 1 0 2 0 -"Weapon Trident" "92290.dat" 0 1 0 0 0 1 0 0 0 1 0 24 0 -"Welding Gas Torch with Hose and Gas Cylinder Top" "13793.DAT" 0 1 0 0 0 1 0 0 0 1 30 35 0 -"Whip" "2488.dat" 0 1 0 0 0 1 0 0 0 1 0 -8 0 -"Whip in Latched Position (Shortcut)" "2488c01.dat" 0 1 0 0 0 1 0 0 0 1 0 -8 0 -"Whip Coiled" "61975.dat" 0 0 0 -1 0 1 0 1 0 0 0 -8 0 -"Wine Glass" "33061.dat" 0 1 0 0 0 1 0 0 0 1 0 -32 0 -"Zip Line Handle" "30229.dat" 0 1 0 0 0 1 0 0 0 1 0 -12 0 - - - -[RHANDA] -"None" "" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"--------------------------------------------------------------------------------" "" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Animal Snake" "30115.dat" 0 -0.469472 0 0.882948 0.882948 0 0.469472 0 1 0 0 -4 4 -"Animal Starfish" "33122.dat" 0 -1 0 0 0 0 1 0 1 0 0 -26 -6 -"Axe with Twin-Blade" "95052.DAT" 0 1 0 0 0 1 0 0 0 1 0 -1 0 -"Battleaxe" "3848.dat" 0 -1 0 0 0 1 0 0 0 -1 0 0 0 -"Bar 0.5L with Blade 3L" "64727.dat" 0 1 0 0 0 1 0 0 0 1 0 -8 0 -"Bar 0.5L with Curved Blade 2L" "87747.dat" 0 1 0 0 0 1 0 0 0 1 0 -8 0 -"Bar 0.5L with Faceted Spike 1L" "88695.dat" 0 1 0 0 0 1 0 0 0 1 0 -8 0 -"Bar 1.5L with Clip" "48729.dat" 0 1 0 0 0 1 0 0 0 1 0 -20 0 -"Bar 3L" "87994.dat" 0 1 0 0 0 1 0 0 0 1 0 -40 0 -"Bar 3L with White Ends Pattern" "87994p01.dat" 0 1 0 0 0 1 0 0 0 1 0 -40 0 -"Bar 4L Light Sabre Blade" "30374.dat" 0 1 0 0 0 -1 0 0 0 -1 0 12 0 -"Bar 4.5L Straight" "71184.dat" 0 1 0 0 0 1 0 0 0 1 0 20 0 -"Bar 4.5L with Handle" "87618.dat" 0 -1 0 0 0 -1 0 0 0 1 0 -80 0 -"Bar 6L with Thick Stop" "63965.dat" 0 1 0 0 0 1 0 0 0 1 0 -8 0 -"Bar 6.6L with Stop" "4095.dat" 0 1 0 0 0 1 0 0 0 1 0 -8 0 -"Barbed Wire Loop" "62700.dat" 0 0 -1 0 -1 0 0 0 0 -1 0 -2 0 -"Batarang" "55707c.dat" 0 0 1 0 -1 0 0 0 0 1 0 -2 0 -"Binoculars with Round Eyepiece" "30162.dat" 0 1 0 0 0 0 -1 0 1 0 -5 -1.6 0 -"Bone 2L" "93160.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Bone 5L" "92691.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Bottle Cylindrical" "95228.dat" 0 1 0 0 0 1 0 0 0 1 0 -12 0 -"Bottle Cylindrical with Bottle Ship Pattern" "95228p01.dat" 0 1 0 0 0 1 0 0 0 1 0 -12 0 -"Bow with Arrow" "4499.dat" 0 0 0 -1 0 1 0 1 0 0 0 1 0 - -; Update 2015-01 -"Brick 1 x 2 x 0.667 with 8 Studs and Angled Handle" "15071.DAT" 0 1 0 0 0 0.920505 0.390731 0 -0.390731 0.920505 0 -11 0 - -"Broom" "4332.dat" 0 -1 0 0 0 1 0 0 0 -1 0 -76 0 -"Bucket 1 x 1 x 1 Conical with Raised Handle" "95343C01.DAT" 0 0 0.642788 -0.766044 1 0 0 0 -0.766044 -0.642788 0 -1.5 0 -"Bucket 1 x 1 x 1 Cylindrical with Raised Handle" "12884C01.DAT" 0 0 0.642788 -0.766044 1 0 0 0 -0.766044 -0.642788 0 -1.5 0 -"Bugle" "71342.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Camera Movie" "30148.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Camera Snapshot" "30089.dat" 0 0 0.5 0.866025 0 0.866025 -0.5 -1 0 0 -4.062 2.5 -18 -"Camera with Side Sight" "4360.dat" 0 0 0 1 0 1 0 -1 0 0 0 -24 6.5 -"Castle Lance" "3849.dat" 0 1 0 0 0 0 1 0 -1 0 0 40 0 -"Chainsaw Blade" "6117.DAT" 0 1 0 0 0 0 -1 0 1 0 0 -11 -8 -"Cheerleader Pom Pom" "87997.DAT" 0 1 0 0 0 1 0 0 0 1 0 5 0 -"Cheerleader Pom Pom with Blue Pattern" "87997p01.DAT" 0 1 0 0 0 1 0 0 0 1 0 5 0 -"Cheerleader Pom Pom with Red Pattern" "87997p02.DAT" 0 1 0 0 0 1 0 0 0 1 0 5 0 -"Circular Blade Saw" "30194.dat" 0 -1 0 0 0 -0.422618 0.906308 0 0.906308 0.422618 0 15 -17 -"Coin with '1' Gothic Type" "96904.dat" 0 0 1 0 0 0 -1 -1 0 0 -2 -4 -10 -"Coin with '2' Gothic Type" "96905.dat" 0 0 1 0 0 0 -1 -1 0 0 -2 -4 -10 -"Coin with '5' Gothic Type" "96906.dat" 0 0 1 0 0 0 -1 -1 0 0 -2 -4 -10 -"Coin with '10' Gothic Type" "96907.dat" 0 0 1 0 0 0 -1 -1 0 0 -2 -4 -10 -"Coin with '10' Sans-serif Type" "70501a.dat" 0 0 1 0 0 0 -1 -1 0 0 -2 -4 -10 -"Coin with '20' Sans-serif Type" "70501b.dat" 0 0 1 0 0 0 -1 -1 0 0 -2 -4 -10 -"Coin with '30' Sans-serif Type" "70501c.dat" 0 0 1 0 0 0 -1 -1 0 0 -2 -4 -10 -"Coin with '40' Sans-serif Type" "70501d.dat" 0 0 1 0 0 0 -1 -1 0 0 -2 -4 -10 -"Conical Flask" "u9180.dat" 0 1 0 0 0 1 0 0 0 1 0 -10 0 -"Conical Flask TransClear with Coloured Base" "u9180c01.dat" 0 1 0 0 0 1 0 0 0 1 0 -10 0 -"Comb" "30112b.dat" 0 1 0 0 0 1 0 0 0 1 0 -1 0 -"Compass" "889c01.dat" 0 1 0 0 0 1 0 0 0 1 0 -3 0 -"Crossbow" "2570.dat" 0 1 0 0 0 1 0 0 0 1 0 -3 0 -"Cup" "3899.dat" 0 1 0 0 0 1 0 0 0 1 0 -15 -20 -"Dagger" "88288.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Dagger with Pearl Light Gray Blade" "88288P01.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Dinner Plate" "6256.dat" 0 -0.0954045 0.866025 0.490814 -0.981627 0 -0.190809 -0.165245 -0.5 0.850114 -7 -5 -26 -"Dynamite Sticks Bundle" "64728.dat" 0 0.5 0 0.866025 0 1 0 -0.866025 0 0.5 0 -28 -9 -"Electric Guitar" "93564.dat" 0 0 0 -1 0 1 0 1 0 0 0 4 0 -"Electric Guitar, Silver Strings, White Body" "93564P01.dat" 0 0 0 -1 0 1 0 1 0 0 0 4 0 -"Electric Guitar, Black Strings, DkPink Lightning" "93564P02.dat" 0 0 0 -1 0 1 0 1 0 0 0 4 0 -"Figure Club" "60659.dat" 0 1 0 0 0 1 0 0 0 1 0 3 0 -"Food Apple" "33051.dat" 0 0.857167 0.515038 0 -0.515038 0.857167 0 0 0 1 14 33 0 -"Food Banana" "33085.dat" 0 0 -1 0 1 0 0 0 0 1 0 0 0 -"Food Carrot" "33172.dat" 0 1 0 0 0 1 0 0 0 1 0 -50 0 -"Food Carrot Top" "33183.dat" 0 1 0 0 0 1 0 0 0 1 0 12 0 -"Food Carrot with Bright_Green Leaves" "33172c02.dat" 0 1 0 0 0 1 0 0 0 1 0 10 0 -"Food Carrot with Green Leaves" "33172c01.dat" 0 1 0 0 0 1 0 0 0 1 0 10 0 -"Food Cherry" "22667.dat" 0 1 0 0 0 1 0 0 0 1 0 -11 0 -"Food Croissant" "33125.dat" 0 0 1 0 -0.819152 0 0.573576 0.573576 0 0.819152 4 -27 -9 -"Food French Bread" "4342.dat" 0 0 0.292372 0.956305 1 0 0 0 0.956305 -0.292372 -4.5 0 5 -"Food Ice Cream Cone" "33120.dat" 0 1 0 0 0 1 0 0 0 1 0 -2 0 -"Food Popsicle" "30222.dat" 0 1 0 0 0 1 0 0 0 1 0 -3 0 -"Food Sausage" "33078.dat" 0 0 -1 0 1 0 0 0 0 1 0 0 0 -"Food Turkey Leg" "33057.dat" 0 0 -0.985 0.174 0 0.174 0.985 -1 0 0 -9 -24 -1 -"Friends Access. Bag Round with Ruffle" "93090.DAT" 0 0 0 -1 1 0 0 0 -1 0 0 -1 -28 -"Friends Access. Bag Round w. Bright Pink Ruffle Pattern" "93090P01.DAT" 0 0 0 -1 1 0 0 0 -1 0 0 -1 -28 -"Friends Access. Bag Round w. Dark Pink Ruffle Pattern" "93090P02.DAT" 0 0 0 -1 1 0 0 0 -1 0 0 -1 -28 -"Friends Access. Bag Round w. Light Aqua Ruffle Pattern" "93090P03.DAT" 0 0 0 -1 1 0 0 0 -1 0 0 -1 -28 -"Friends Access. Basket" "93092.DAT" 0 1 0 0 0 0 1 0 -1 0 15 -2 -29 -"Friends Access. Comb with Handle and 3 Hearts" "96482.DAT" 0 1 0 0 0 1 0 0 0 1 0 9 0 -"Friends Access. Cupcake Case" "97784.DAT" 0 1 0 0 0 1 0 0 0 1 0 -3 0 -"Friends Access. Cutlery Fork" "97781.DAT" 0 0 0 1 0 1 0 -1 0 0 0 -1 0 -"Friends Access. Cutlery Knife" "97782.DAT" 0 1 0 0 0 1 0 0 0 1 0 -1 0 -"Friends Access. Dish Rectangular" "97785.DAT" 0 1 0 0 0 1 0 0 0 1 0 -12 0 -"Friends Access. Dish Round 2.7 x 2.7" "97783.DAT" 0 1 0 0 0 1 0 0 0 1 0 -12 0 -"Friends Access. Frying Pan" "97790.DAT" 0 0 0 1 -1 0 0 0 -1 0 0 -56 -12 -"Friends Access. Hair Brush with Heart on Reverse" "96480.DAT" 0 0 0 1 0 1 0 -1 0 0 0 9 0 -"Friends Access. Hair Dryer" "96484.DAT" 0 1 0 0 0 1 0 0 0 1 0 8 0 -"Friends Access. Hand-held Food Mixer" "97793.DAT" 0 1 0 0 0 0 1 0 -1 0 0 -3 0 -"Friends Access. Lipstick with Light Bluish Grey Handle" "93094.DAT" 0 1 0 0 0 1 0 0 0 1 0 6 0 -"Friends Access. Mixing Bowl" "97791.DAT" 0 1 0 0 0 1 0 0 0 1 0 -12 0 -"Friends Access. Spatula with 3 Holes" "97787.DAT" 0 1 0 0 0 1 0 0 0 1 0 -1 0 -"Frypan" "4528.dat" 0 0 1 0 0 0 1 1 0 0 -4 -24 0 -"Goblet" "2343.dat" 0 1 0 0 0 1 0 0 0 1 0 -26 0 -"Goblet with Hollow Stem" "6269.dat" 0 1 0 0 0 1 0 0 0 1 0 -26 0 -"Gun Flintlock Pistol" "2562.dat" 0 1 0 0 0 1 0 0 0 1 0 -1 0 -"Gun Laser Kryptonian" "13952.DAT" 0 1 0 0 0 1 0 0 0 1 0 2 0 -"Gun Laser Pistol" "87993.dat" 0 1 0 0 0 1 0 0 0 1 0 -4 0 -"Gun Long Blaster" "57899.dat" 0 1 0 0 0 1 0 0 0 1 0 -20 0 -"Gun Musket" "2561.dat" 0 0 0.707 0.707 0 0.707 -0.707 -1 0 0 -25.1 -33.7 0 -"Gun Revolver" "30132.dat" 0 1 0 0 0 1 0 0 0 1 0 -3 0 -"Gun Rifle" "30141.dat" 0 0 0 1 0 1 0 -1 0 0 0 -8 0 -"Gun Semiautomatic Pistol" "55707a.dat" 0 1 0 0 0 1 0 0 0 1 0 -20 0 -"Gun Shooting Blaster with Dark Bluish Grey Trigger" "15391c01.DAT" 0 1 0 0 0 1 0 0 0 1 0 4 0 -"Gun Shooting Blaster with Trigger and TrOrange Projectile" "15391C02.DAT" 0 1 0 0 0 1 0 0 0 1 0 4 0 -"Gun SW Short Blaster" "58247.dat" 0 1 0 0 0 1 0 0 0 1 0 -3 0 -"Gun SW Small Blaster DC-17" "61190a.dat" 0 1 0 0 0 1 0 0 0 1 0 -3 0 -"Hairbrush" "3852.dat" 0 -1 0 0 0 1 0 0 0 -1 2.7 -8 0 -"Hand Fan" "93553.dat" 0 1 0 0 0 1 0 0 0 1 0 2 0 -"Hand Truck (Shortcut)" "2495c01.dat" 0 1 0 0 0 0 1 0 -1 0 -22 -4 -58 -"Handcuffs" "61482.dat" 0 1 0 0 0 1 0 0 0 1 -24 16 12 -"Harpoon" "57467.dat" 0 1 0 0 0 1 0 0 0 1 0 28 0 -"Hose Nozzle with Side String Hole" "58367.dat" 0 1 0 0 0 1 0 0 0 1 0 -2 0 -"Hose Nozzle with Side String Hole Simplified" "60849.dat" 0 1 0 0 0 1 0 0 0 1 0 -2 0 -"Ice Axe" "30193.dat" 0 1 0 0 0 1 0 0 0 1 0 6 0 -"Jackhammer" "30228.dat" 0 0.326 0 -0.946 0.899 -0.309 0.31 -0.292 -0.951 -0.101 -2.5 -18.5 11 -"Key" "62808.DAT" 0 1 0 0 0 1 0 0 0 1 0 -2 0 -"Knife" "37.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Knife with Flat Hilt End" "95054.DAT" 0 1 0 0 0 1 0 0 0 1 0 -3 0 -"Ladle" "4337.dat" 0 1 0 0 0 1 0 0 0 1 0 -36 0 -"Life Ring" "30340.dat" 0 0 -1 0 0 0 1 -1 0 0 4 16 -21 -"Lightning" "59233.dat" 0 1 0 0 0 1 0 0 0 1 0 -2 0 -"Lightsaber Chrome Silver - 1 Side On" "577Bc01.dat" 0 1 0 0 0 1 0 0 0 1 0 -20 0 -"Lightsaber Chrome Silver - 2 Sides On" "577Bc02.dat" 0 1 0 0 0 1 0 0 0 1 0 -20 0 -"Lightsaber Hilt with Bottom Ring" "577B.dat" 0 1 0 0 0 1 0 0 0 1 0 -20 0 -"Long Bow with Arrow" "93231.dat" 0 0.966 0 0.259 0 1 0 -0.259 0 0.966 0 -11 0 -"Loudhailer" "4349.dat" 0 1 0 0 0 1 0 0 0 1 0 -16 0 -"Loudhailer with Orange Stripe Pattern" "4349P01.DAT" 0 1 0 0 0 1 0 0 0 1 0 -16 0 -"Machine Gun with Drum Magazine" "55707b.dat" 0 1 0 0 0 1 0 0 0 1 0 -16 0 -"Magic Wand" "6124.dat" 0 1 0 0 0 1 0 0 0 1 0 8 0 -"Maracas" "90508.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Maracas with Green Border" "90508P01.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Medical Thermometer" "98393D.DAT" 0 0 0 1 0 1 0 -1 0 0 0 -26 -5 -"Metal Detector" "4479.dat" 0 1 0 0 0 1 0 0 0 1 0 -24 0 -"Microphone" "90370.dat" 0 1 0 0 0 1 0 0 0 1 0 -8 0 -"Microphone with Metallic Silver Top" "90370p01.dat" 0 1 0 0 0 1 0 0 0 1 0 -8 0 -"Mug" "33054.dat" 0 1 0 0 0 1 0 0 0 1 0 -12 -20 -"Pharaoh's Staff with Forked End" "93252.dat" 0 1 0 0 0 1 0 0 0 1 0 -42 0 -"Paint Brush" "93552.dat" 0 1 0 0 0 1 0 0 0 1 0 16 0 -"Paint Brush w. Silver Ring, Green Tip" "93552P01.dat" 0 1 0 0 0 1 0 0 0 1 0 16 0 -"Paint Palette" "93551.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Paint Palette with Paint Drops Pattern" "93551P01.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Paint Roller Brush Handle" "12885.dat" 0 1 0 0 0 1 0 0 0 1 0 8 0 -"Pike / Spear Elaborate with Metallic Silver Head" "90391P01.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Pike / Spear Elaborate with Flat Silver Head" "90391P02.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Pipe Wrench" "4328.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Pitchfork" "4496.dat" 0 1 0 0 0 1 0 0 0 1 0 -12 0 -"Plant Flower Stem w. Bar w. 3 Flowers" "99249C01.DAT" 0 1 0 0 0 1 0 0 0 1 0 6 0 -"Plant Flower Stem w. Bar w. 3 Flowers w. 6 Rounded Petals" "99249C03.DAT" 0 1 0 0 0 1 0 0 0 1 0 6 0 -"Plant Flower Stem w. Bar w. 3 Roses" "99249C02.DAT" 0 1 0 0 0 1 0 0 0 1 0 6 0 -"Plunger" "11459.DAT" 0 1 0 0 0 -1 0 0 0 -1 0 -20 0 -"Plunger with Medium Dark Flesh Handle" "11459P01.DAT" 0 1 0 0 0 -1 0 0 0 -1 0 -20 0 -"Polearm Halberd" "6123.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Pushbroom" "3836.dat" 0 0 0 -1 0 -1 0 -1 0 0 0 44 0 -"Radio with Long Handle" "3962b.dat" 0 0 0 -1 0 1 0 1 0 0 0 -1 0 -"Radio with Short Handle" "3962a.dat" 0 0 0 -1 0 1 0 1 0 0 0 -1 0 -"Ring 1 x 1" "11010.dat" 0 0 -1 0 -1 0 0 0 0 -1 -4 -2 -6 -"Ring with Triangle" "87748.dat" 0 0 -1 0 0.866025 0 -0.5 0.5 0 0.866026 0 -2 -25 -"Ring with Triangle with Gold Bands and Crab Pattern" "87748P01.dat" 0 0 -1 0 0.866025 0 -0.5 0.5 0 0.866026 0 -2 -25 -"Ring with Triangle with Gold Bands and Manta Ray Pattern" "87748P05.dat" 0 0 -1 0 0.866025 0 -0.5 0.5 0 0.866026 0 -2 -25 -"Ring with Triangle with Gold Bands and Shark Pattern" "87748P03.dat" 0 0 -1 0 0.866025 0 -0.5 0.5 0 0.866026 0 -2 -25 -"Ring with Triangle with Gold Bands and Squid Pattern" "87748P04.dat" 0 0 -1 0 0.866025 0 -0.5 0.5 0 0.866026 0 -2 -25 -"Ring with Triangle with Gold Bands and Triangle Pattern" "87748P06.dat" 0 0 -1 0 0.866025 0 -0.5 0.5 0 0.866026 0 -2 -25 -"Ring with Triangle with Gold Bands and Turtle Pattern" "87748p02.dat" 0 0 -1 0 0.866025 0 -0.5 0.5 0 0.866026 0 -2 -25 -"Rock 1 x 1 Gem Facetted" "30153.dat" 0 1 0 0 0 1 0 0 0 1 0 -8 0 -"Saucepan" "4529.dat" 0 0 1 0 0 0 1 1 0 0 -6 -24 0 -"Saxophone" "13808.DAT" 0 1 0 0 0 1 0 0 0 1 0 7 0 -"Saxophone with Black Mouthpiece" "13808P01.DAT" 0 1 0 0 0 1 0 0 0 1 0 7 0 -"Sextant" "30154.dat" 0 0 0 1 0 1 0 -1 0 0 0 -35 0 -"Shield Broad with Spiked Bottom and Cutout Corner" "10049.dat" 0 0 0 -1 1 0 0 0 -1 0 4 -1 0 -"Shield Broad w. Spiked Bottom, Cutout Corner, Hand Pattern" "10049P01.dat" 0 0 0 -1 1 0 0 0 -1 0 4 -1 0 -"Shield Octagonal with Stud" "48494.dat" 0 0 0 -1 1 0 0 0 -1 0 0 -2 0 -"Shield Octagonal without Stud" "61856.dat" 0 0 0 -1 1 0 0 0 -1 0 0 -2 0 -"Shield Octagonal with Troll Skull on Dark Red Pattern" "61856P40.dat" 0 0 0 -1 1 0 0 0 -1 0 0 -2 0 -"Shield Oval" "92747.dat" 0 0 0 -1 1 0 0 0 -1 0 4 -1 0 -"Shield Oval with SW Gungan Patrol Shield" "92747p01.dat" 0 0 0 -1 1 0 0 0 -1 0 4 -1 0 -"Shield Ovoid" "2586.dat" 0 0 0 -1 1 0 0 0 -1 0 4 -1 0 -"Shield Ovoid with American Indian Pattern" "2586pw1.dat" 0 0 0 -1 1 0 0 0 -1 0 4 -1 0 -"Shield Ovoid with Bat Pattern" "2586P4F.dat" 0 0 0 -1 1 0 0 0 -1 0 4 -1 0 -"Shield Ovoid with Blue Dragon Pattern" "2586p4c.dat" 0 0 0 -1 1 0 0 0 -1 0 4 -1 0 -"Shield Ovoid with Bull Head Pattern" "2586P4G.DAT" 0 0 0 -1 1 0 0 0 -1 0 4 -1 0 - -; Update 2015-01 -"Shield Ovoid with Bull Head on Brown Border Sticker" "2586D01.DAT" 0 0 0 -1 1 0 0 0 -1 0 4 -1 0 - -"Shield Ovoid with Crown on Dark/Med Blue Quarters Pattern" "2586P4J.DAT" 0 0 0 -1 1 0 0 0 -1 0 4 -1 0 -"Shield Ovoid with DkGreen Dragon on MdDkFlesh/Tan Pattern" "2586P4K.DAT" 0 0 0 -1 1 0 0 0 -1 0 4 -1 0 -"Shield Ovoid with Golden Lion Pattern" "2586ph1.DAT" 0 0 0 -1 1 0 0 0 -1 0 4 -1 0 -"Shield Ovoid with Gold Lion on Red/White Quarters Pattern" "2586P4L.DAT" 0 0 0 -1 1 0 0 0 -1 0 4 -1 0 -"Shield Ovoid with Green Dragon Pattern" "2586p4b.dat" 0 0 0 -1 1 0 0 0 -1 0 4 -1 0 -"Shield Ovoid with Indigo Islanders Pattern" "2586P30.dat" 0 0 0 -1 1 0 0 0 -1 0 4 -1 0 -"Shield Ovoid with Royal Knights Lion Pattern" "2586p4d.dat" 0 0 0 -1 1 0 0 0 -1 0 4 -1 0 -"Shield Ovoid with Silver Skull on Dark Red Pattern" "2586P4H.DAT" 0 0 0 -1 1 0 0 0 -1 0 4 -1 0 -"Shield Ovoid with Silver Snake Pattern" "2586PH2.DAT" 0 0 0 -1 1 0 0 0 -1 0 4 -1 0 -"Shield Ovoid with SW Gungans Patrol Pattern" "2586ps1.DAT" 0 0 0 -1 1 0 0 0 -1 0 4 -1 0 -"Shield Rectangular Curved with Stud" "98367.DAT" 0 0 0 -1 1 0 0 0 -1 0 0 -1 0 -"Shield Round" "3876.dat" 0 0 0 -1 0 1 0 1 0 0 0 -12 0 -"Shield Round Bowed" "75902.dat" 0 0 0 -1 1 0 0 0 -1 0 4 -1 0 -"Shield Round Bowed with Bullseye with Star Pattern" "75902P02.dat" 0 0 0 -1 1 0 0 0 -1 0 4 -1 0 -"Shield Round Bowed with DkGreen and Gold Rohan" "75902P01.dat" 0 0 0 -1 1 0 0 0 -1 0 4 -1 0 -"Shield Round Bowed with Gold Eagle Pattern" "75902P03.DAT" 0 0 0 -1 1 0 0 0 -1 0 4 -1 0 -"Shield Round Bowed with Mercedes-Benz Logo" "75902P04.DAT" 0 0 0 -1 1 0 0 0 -1 0 4 -1 0 -"Shield Round Flat" "59231.dat" 0 0 0 -1 0 1 0 1 0 0 10 -12 0 -"Shield Round Flat with Silver Skull on Dark Red Pattern" "59231P4H.dat" 0 0 0 -1 0 1 0 1 0 0 10 -12 0 -"Shield Round Type 2" "91884.DAT" 0 0 0 -1 1 0 0 0 -1 0 4 -2 0 -"Shield Round Type 2 w. Aztec Bird on Dark Red Pattern" "91884P04.DAT" 0 0 0 -1 1 0 0 0 -1 0 4 -2 0 -"Shield Round Type 2 w. DkBrown Ring and 4 Rivets Pattern" "91884P01.DAT" 0 0 0 -1 1 0 0 0 -1 0 4 -2 0 -"Shield Round Type 2 w. Dragon Heads and Ornaments Pattern" "91884P03.DAT" 0 0 0 -1 1 0 0 0 -1 0 4 -2 0 -"Shield Round Type 2 w. Silver Rivets Pattern" "91884P02.DAT" 0 0 0 -1 1 0 0 0 -1 0 4 -2 0 -"Shield Scarab" "93251.dat" 0 0 0 -1 1 0 0 0 -1 0 9 -1 -1 -"Shield Triangular" "3846.dat" 0 0 0 -1 0 1 0 1 0 0 0 -12 0 -"Shield Triangular with Bat Pattern" "3846p4f.dat" 0 0 0 -1 0 1 0 1 0 0 0 -12 0 -"Shield Triangular with Black Falcon Blue Border Pattern" "3846p45.dat" 0 0 0 -1 0 1 0 1 0 0 0 -12 0 -"Shield Triangular with Black Falcon Yellow Border Pattern" "3846p46.dat" 0 0 0 -1 0 1 0 1 0 0 0 -12 0 -"Shield Triangular with Blue Dragon Pattern" "3846p4c.dat" 0 0 0 -1 0 1 0 1 0 0 0 -12 0 -"Shield Triangular with Blue Lion on Yellow Background" "3846p4g.dat" 0 0 0 -1 0 1 0 1 0 0 0 -12 0 -"Shield Triangular with Crown on Dark/Med Blue Quarters" "3846P4J.dat" 0 0 0 -1 0 1 0 1 0 0 0 -12 0 -"Shield Triangular with Crown on Dark-Pink Sticker" "3846d01.dat" 0 0 0 -1 0 1 0 1 0 0 0 -12 0 -"Shield Triangular with Crown on Violet Sticker" "3846d05.dat" 0 0 0 -1 0 1 0 1 0 0 0 -12 0 -"Shield Triangular with Dragon on MdDkFlesh/Tan Pattern" "3846P4K.dat" 0 0 0 -1 0 1 0 1 0 0 0 -12 0 -"Shield Triangular with Forestman Pattern" "3846p48.dat" 0 0 0 -1 0 1 0 1 0 0 0 -12 0 -"Shield Triangular w. Gold Lion on Red/White Quart. Patt." "3846P4L.dat" 0 0 0 -1 0 1 0 1 0 0 0 -12 0 -"Shield Triangular with Green Chevrons on Yellow Sticker" "3846d03.dat" 0 0 0 -1 0 1 0 1 0 0 0 -12 0 -"Shield Triangular with Green Chevrons on Yellow.LtGray" "3846d06.dat" 0 0 0 -1 0 1 0 1 0 0 0 -12 0 -"Shield Triangular with Lion Head, Blue & Yellow Pattern" "3846p4e.dat" 0 0 0 -1 0 1 0 1 0 0 0 -12 0 -"Shield Triangular with Maroon/Red Quarters Pattern" "3846p4u.dat" 0 0 0 -1 0 1 0 1 0 0 0 -12 0 -"Shield Triangular with Red and Gray Pattern, Blue Frame" "3846p47.dat" 0 0 0 -1 0 1 0 1 0 0 0 -12 0 -"Shield Triangular with Red Cross and Helmet" "3846p01.dat" 0 0 0 -1 0 1 0 1 0 0 0 -12 0 -"Shield Triangular with Red/Peach Quarters Pattern" "3846p4t.dat" 0 0 0 -1 0 1 0 1 0 0 0 -12 0 -"Shield Triangular with Royal Knights Lion Pattern" "3846p4d.dat" 0 0 0 -1 0 1 0 1 0 0 0 -12 0 -"Shield Triangular with White Maltese Cross on Red Sticker" "3846d02.dat" 0 0 0 -1 0 1 0 1 0 0 0 -12 0 -"Shield Triangular with Wolfpack Pattern" "3846p44.dat" 0 0 0 -1 0 1 0 1 0 0 0 -12 0 -"Shield Triangular with Yellow Lion on Blue Background" "3846p4h.dat" 0 0 0 -1 0 1 0 1 0 0 0 -12 0 -"Shield Triangular with Yellow Trefoils on Blue Sticker" "3846d04.dat" 0 0 0 -1 0 1 0 1 0 0 0 -12 0 -"Shield Triangular with Yellow Trefoils on DkBlue Sticker" "3846d07.dat" 0 0 0 -1 0 1 0 1 0 0 0 -12 0 -"Shovel" "3837.dat" 0 1 0 0 0 1 0 0 0 1 0 -12 0 -"Signal Holder" "3900.dat" 0 1 0 0 0 0 -1 0 1 0 0 -36 -2 -"Signal Holder with Black 'POLICE' and Red Line Pattern" "3900P01.DAT" 0 1 0 0 0 0 -1 0 1 0 0 -36 -2 -"Signal Holder with Green Circle on White Sticker" "3900d01.dat" 0 1 0 0 0 0 -1 0 1 0 0 -36 -2 -"Ski Pole" "90540.dat" 0 1 0 0 0 1 0 0 0 1 0 -8 0 -"Sledgehammer" "75904.dat" 0 0 0 1 0 1 0 -1 0 0 0 -14 0 -"Small Bow with Arrow" "95051.DAT" 0 0 0 1 0 1 0 -1 0 0 0 -10 0 -"Space Scanner Tool" "30035.dat" 0 1 0 0 0 1 0 0 0 1 0 -19 -10 -"Spear" "4497.dat" 0 1 0 0 0 1 0 0 0 1 0 -40 0 -"Spear with Four Side Blades" "43899.dat" 0 1 0 0 0 1 0 0 0 1 0 -144 0 -"Speargun" "30088.dat" 0 1 0 0 0 1 0 0 0 1 0 -13 0 -"Staff with Crescent End" "95050.DAT" 0 1 0 0 0 1 0 0 0 1 0 -1 0 -"Staff with Spherical End" "95049.DAT" 0 1 0 0 0 1 0 0 0 1 0 -1 0 -"Steak on Bone" "98372.dat" 0 1 0 0 0 1 0 0 0 1 0 -2 0 -"Steak on Bone with Red Meat" "98372P01.dat" 0 1 0 0 0 1 0 0 0 1 0 -2 0 -"Statuette" "90398.dat" 0 1 0 0 0 1 0 0 0 1 0 -1 0 -"Stretcher with Bottom Hinges" "4714.DAT" 0 0 0 -1 1 0 0 0 -1 0 -26 -74 -2 -"Stretcher without Bottom Hinges" "93140.DAT" 0 0 0 -1 1 0 0 0 -1 0 -26 -74 -2 -"Suitcase" "4449.dat" 0 0 0 -1 1 0 0 0 -1 0 0 0 0 -"Sword Cutlass" "2530.dat" 0 1 0 0 0 1 0 0 0 1 0 -2 0 -"Sword Greatsword" "59.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Sword Katana Type 1 (Octogonal Guard)" "30173a.dat" 0 1 0 0 0 1 0 0 0 1 0 6 0 -"Sword Katana Type 2 (Square Guard)" "30173b.dat" 0 1 0 0 0 1 0 0 0 1 0 6 0 -"Sword Khopesh" "93247.dat" 0 1 0 0 0 1 0 0 0 1 0 -8 0 -"Sword Longsword" "98370.dat" 0 1 0 0 0 1 0 0 0 1 0 -8 0 -"Sword Rapier" "93550.dat" 0 1 0 0 0 1 0 0 0 1 0 -2 0 -"Sword Roman Gladius" "95673.dat" 0 1 0 0 0 1 0 0 0 1 0 -8 0 -"Sword Saber with Clip Pommel" "59229.dat" 0 1 0 0 0 1 0 0 0 1 0 -2 0 -"Sword Scimitar" "43887.dat" 0 1 0 0 0 1 0 0 0 1 0 -18 0 -"Sword Scimitar with Jagged Edge" "60752.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Sword Shortsword" "3847.dat" 0 1 0 0 0 1 0 0 0 1 0 -12 0 -"Sword Small with Angular Guard" "95053.DAT" 0 1 0 0 0 1 0 0 0 1 0 -3 0 -"Sword Small with Curved Blade" "10053.DAT" 0 1 0 0 0 1 0 0 0 1 0 -2 0 -"Sword Uruk-Hai" "10050.dat" 0 -1 0 0 0 1 0 0 0 -1 0 4 0 -"Sword Sword with Angular Hilt" "48495.dat" 0 0 0 -1 0 1 0 1 0 0 0 -10 0 -"Syringe" "87989.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Telescope" "64644.dat" 0 1 0 0 0 1 0 0 0 1 0 -11 0 -"Tennis Racket" "93216.dat" 0 1 0 0 0 1 0 0 0 1 0 -3 0 -"Tomahawk with Flat-Silver Blade" "13571.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Tool 4-Way Lug Wrench" "604553.DAT" 0 1 0 0 0 1 0 0 0 1 0 -12 0 -"Tool Adjustable Wrench with 3-Rib Handle" "604614.DAT" 0 1 0 0 0 1 0 0 0 1 0 -2 0 -"Tool Battery Powered Drill" "604549.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Tool Binoculars Space" "30304.dat" 0 1 0 0 0 0 -1 0 1 0 -5 -1 0 -"Tool Box Wrench" "55300.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Tool Box Wrench with 3-Rib Handle" "604552.DAT" 0 1 0 0 0 1 0 0 0 1 0 -2 0 - -; Update 2015-01 -"Tool Crowbar" "92585.DAT" 0 1 0 0 0 1 0 0 0 1 0 -30 0 - -"Tool Fishing Rod" "2614.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Tool Grappling Hook" "30192.dat" 0 1 0 0 0 -1 0 0 0 -1 0 9 0 -"Tool Hammer" "55295.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Tool Hammer with 3-Rib Handle" "604547.DAT" 0 1 0 0 0 1 0 0 0 1 0 -2 0 -"Tool Handaxe" "3835.dat" 0 1 0 0 0 1 0 0 0 1 0 -16 0 -"Tool Hose Nozzle with Handle" "4210a.dat" 0 -1 0 0 0 1 0 0 0 -1 0 -12 0 -"Tool Magnifying Glass" "30152.dat" 0 1 0 0 0 1 0 0 0 1 0 -52 0 -"Tool Mallet" "4522.dat" 0 0 0 1 0 1 0 -1 0 0 0 -28 0 -"Tool Oar" "2542.dat" 0 -1 0 0 0 -1 0 0 0 1 0 40 0 -"Tool Oilcan" "55296.DAT" 0 1 0 0 0 1 0 0 0 1 0 -6 0 -"Tool Oilcan with Ribbed Handle" "604548.DAT" 0 1 0 0 0 1 0 0 0 1 0 -3 0 -"Tool Open End Wrench" "55299.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Tool Open End Wrench with 3-Rib Handle" "604551.DAT" 0 1 0 0 0 1 0 0 0 1 0 -2 0 -"Tool Pickaxe" "3841.dat" 0 1 0 0 0 1 0 0 0 1 0 -12 0 -"Tool Power Drill" "55297.dat" 0 1 0 0 0 1 0 0 0 1 0 -6 0 -"Tool Screwdriver" "55298.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Tool Screwdriver with Wide Head and 3-Rib Handle" "604550.DAT" 0 1 0 0 0 1 0 0 0 1 0 -2 0 -"Tool Socket Wrench with Ratchet and 3-Rib Handle" "604615.DAT" 0 1 0 0 0 1 0 0 0 1 0 -2 0 -"Tool Spanner/Screwdriver" "4006.dat" 0 0 0 -1 0 1 0 1 0 0 0 -14 0 -"Toolbox 1 x 3 with Handle" "98368.dat" 0 0 0 1 -1 0 0 0 -1 0 0 -2 0 -"Torch" "3959.dat" 0 1 0 0 0 1 0 0 0 1 0 -13 0 -"Torch without Grooves" "86208.dat" 0 1 0 0 0 1 0 0 0 1 0 -13 0 -"Toy Winder Key" "98375.dat" 0 0 0 -1 1 0 0 0 -1 0 0 -2 -20 -"Tray Oval" "11252.dat" 0 0 1 0 -1 0 0 0 0 1 6 -3 -16 -"Underwater Scooter" "30092.dat" 0 -1 0 0 0 1 0 0 0 -1 -20 -22 -8.5 -"Weapon Billy Club" "13790.DAT" 0 1 0 0 0 1 0 0 0 1 0 -7.5 0 -"Weapon Bladed Claw" "88811.dat" 0 1 0 0 0 1 0 0 0 1 0 2 0 -"Weapon Club with Spikes" "88001.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Weapon Crescent Blade Serrated with Bar 0.5L" "98141.dat" 0 1 0 0 0 1 0 0 0 1 0 2 0 -"Weapon Curved Blade 8.5L with Bar 1.5L" "98137.dat" 0 1 0 0 0 1 0 0 0 1 0 12 0 -"Weapon Hand Dagger" "88812.dat" 0 1 0 0 0 1 0 0 0 1 0 2 0 -"Weapon Trident" "92290.dat" 0 1 0 0 0 1 0 0 0 1 0 24 0 -"Welding Gas Torch with Hose and Gas Cylinder Top" "13793.DAT" 0 1 0 0 0 1 0 0 0 1 30 35 0 -"Whip" "2488.dat" 0 1 0 0 0 1 0 0 0 1 0 -8 0 -"Whip in Latched Position (Shortcut)" "2488c01.dat" 0 1 0 0 0 1 0 0 0 1 0 -8 0 -"Whip Coiled" "61975.dat" 0 0 0 -1 0 1 0 1 0 0 0 -8 0 -"Wine Glass" "33061.dat" 0 1 0 0 0 1 0 0 0 1 0 -32 0 -"Zip Line Handle" "30229.dat" 0 1 0 0 0 1 0 0 0 1 0 -12 0 - - - -[LLEG] -"Plain Leg" "3816.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"3 Black Diamonds Pattern" "3816pba.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Astro Pattern" "3816P6F.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Blue/White Triangles, Fringe Pattern" "3816PW2.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Buttoned Pocket Pattern" "3816PA3.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Chainlink and 3 Safety Pins Pattern" "3816PC44.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Clockwork Robot Pattern" "3816PC67.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"DarkBlue Loincloth Pattern" "3816PQ0.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"DarkBlue and Gold Loincloth Pattern" "3816PQ1.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"DarkRed Loincloth, White Claws and Fur Tail Pattern" "3816PAW.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"DarkTurquoise/White Triangles, White Fringe Pattern" "3816PW3.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Golden Circuit Pattern" "3816P6W.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Grass Skirt Pattern" "3816p3j.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Green Kilt and Toes Pattern" "3816pa2.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Holster and Belt Pattern" "3816PA9.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Iron Man Armoured Suit Mark VI Pattern" "3816PBB.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Iron Man Armoured Suit Mark VII Pattern" "3816PBC.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Iron Man Armoured Suit Mark XLII Pattern" "3816PBF.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Iron Man Armoured Suit Mark XVII Pattern" "3816PBE.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Iron Patriot Armoured Suit Kneepad Pattern" "3816PBG.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Laboratory Smock Pattern" "3816PDE.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Leather Straps (Red Studs) Pattern" "3816p4f.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"LOTR Coat and Shirttails Pattern" "3816PM2.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"LOTR Leather Armor Pattern" "3816PM0.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"LOTR Scale Armor Pattern" "3816PM1.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Orange Cable Pattern" "3816P6u.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Purple Greatcoat Pattern" "3816phb.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Red/White Triangles Pattern" "3816PW1.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 - -; Update 2015-01 -"Reflective Stripe Pattern" "3816P8H.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Reflective Stripe and Triangles on Feet Pattern" "3816P8I.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 - -"Robot Pattern" "3816P63.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Salmon Cable Pattern" "3816P6V.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"SW Gunbelt Pattern" "3816ps5.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"SW Stormtrooper Pattern" "3816PSK.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"SW White Leggings Pattern" "3816PS0.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"War Machine Armoured Suit Kneepad Pattern" "3816PBD.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"White Apron Pattern" "3816P89.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 - -; Update 2015-01 -"White and Gold Markings Pattern" "3816P6G.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 - - -"--------------------Non-standard legs-------------------------------------------" "" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Leg Skeleton" "6266.DAT" 0 1 0 0 0 1 0 0 0 1 -10 0 0 -"Leg Wooden" "2532.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Mechanical Leg" "53984.DAT" 0 1 0 0 0 1 0 0 0 1 -10 44 -10 -"--------------------------------------------------------------------------------" "" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Hips and Legs Short -> Hips:" "" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Legs Old -> Hips:" "" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Mechanical Legs -> Hips:" "" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Skirts (Slope Brick 65 2 x 2 x 2) -> Hips:" "" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"--------------------------------------------------------------------------------" "" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"None" "" 0 1 0 0 0 1 0 0 0 1 0 0 0 - - - -[RLEG] -"Plain Leg" "3817.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"2 Red Diamonds Pattern" "3817PBA.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"2 Safety Pins Pattern" "3817PC44.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Astro Pattern" "3817P6F.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Blue/White Triangles, Fringe Pattern" "3817PW2.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Buttoned Pocket Pattern" "3817PA3.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Clockwork Robot Pattern" "3817PC67.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"DarkBlue Loincloth Pattern" "3817PQ0.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"DarkBlue and Gold Loincloth Pattern" "3817PQ1.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"DarkRed Loincloth and White Claws Pattern" "3817PAW.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"DarkTurquoise/White Triangles, White Fringe Pattern" "3817PW3.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 - -; Update 2015-01 -"'EMMET' Badge, Reflective Stripe Pattern" "3817P8H.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"'EMMET' Badge, Reflective Stripe, Silver Triangles Pattern""3817P8I.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 - -"Golden Circuit Pattern" "3817P6W.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Grass Skirt Pattern" "3817p3j.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Green Kilt and Toes Pattern" "3817pa2.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Holster and Belt Pattern" "3817PA9.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Iron Man Armoured Suit Mark VI Pattern" "3817PBB.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Iron Man Armoured Suit Mark VII Pattern" "3817PBC.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Iron Man Armoured Suit Mark XLII Pattern" "3817PBF.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Iron Man Armoured Suit Mark XVII Pattern" "3817PBE.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Iron Patriot Armoured Suit Kneepad Pattern" "3817PBG.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Laboratory Smock Pattern" "3817PDE.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Leather Straps (Red Studs) Pattern" "3817p4f.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"LOTR Coat and Shirttails Pattern" "3817PM2.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"LOTR Leather Armor Pattern" "3817PM0.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"LOTR Scale Armor Pattern" "3817PM1.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Orange Cable Pattern" "3817P6u.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Purple Greatcoat Pattern" "3817phb.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Red/White Triangles Pattern" "3817PW1.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Robot Pattern" "3817P63.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Salmon Cable Pattern" "3817P6V.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"SW Stormtrooper Pattern" "3817PSK.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"SW White Leggings Pattern" "3817PS0.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"War Machine Armoured Suit Kneepad Pattern" "3817PBD.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"White Apron Pattern" "3817P89.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 - -"--------------------Non-standard legs-------------------------------------------" "" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Leg Wooden" "2532.DAT" 0 -1 0 0 0 1 0 0 0 -1 0 0 0 -"Leg Skeleton" "6266.DAT" 0 1 0 0 0 1 0 0 0 1 10 0 0 -"Mechanical Leg" "53984.DAT" 0 1 0 0 0 1 0 0 0 1 10 44 -10 -"--------------------------------------------------------------------------------" "" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Hips and Legs Short -> Hips:" "" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Legs Old -> Hips:" "" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Mechanical Legs -> Hips:" "" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Skirts (Slope Brick 65 2 x 2 x 2) -> Hips:" "" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"--------------------------------------------------------------------------------" "" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"None" "" 0 1 0 0 0 1 0 0 0 1 0 0 0 - - - -[LLEGA] -"None" "" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"--------------------------------------------------------------------------------" "" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Flipper" "2599.DAT" 0 0.996 0 0.087 0 1 0 -0.087 0 0.996 -10 28 -1 -"Roller Skate" "11253.DAT" 0 1 0 0 0 1 0 0 0 1 -10 28 -1 -"Skate" "93555.DAT" 0 1 0 0 0 1 0 0 0 1 -10 28 -1 -"Skateboard with Black Wheels (Shortcut)" "42511c01.DAT" 0 1 0 0 0 1 0 0 0 1 0 28 1 -"Snowshoe" "30284.DAT" 0 1 0 0 0 1 0 0 0 1 -10 28 -1 -"Ski" "6120.DAT" 0 1 0 0 0 1 0 0 0 1 -10 28 1 - -; Update 2015-01 -"Ski 4L without Hinge" "99774.DAT" 0 1 0 0 0 1 0 0 0 1 -10 28 -1 - -"Ski 6L" "90509.DAT" 0 1 0 0 0 1 0 0 0 1 -10 28 -1 -"--------------------Non-standard accessories------------------------------------" "" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Plate 2x4 with Curved Beveled Sides" "88000.DAT" 0 1 0 0 0 1 0 0 0 1 0 28 0 -"Surf Board 2 x 6.5" "90397.DAT" 0 0 0 1 0 1 0 -1 0 0 0 28 -1 -"Surf Board 2 x 6.5 with Pink Flames Pattern" "90397P02.DAT" 0 0 0 1 0 1 0 -1 0 0 0 28 -1 -"Surf Board 2 x 10" "6075.DAT" 0 -1 0 0 0 1 0 0 0 -1 0 28 -1 - - -[RLEGA] -"None" "" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"--------------------------------------------------------------------------------" "" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Flipper" "2599.DAT" 0 0.996 0 -0.087 0 1 0 0.087 0 0.996 10 28 -1 -"Roller Skate" "11253.DAT" 0 1 0 0 0 1 0 0 0 1 10 28 -1 -"Skate" "93555.DAT" 0 1 0 0 0 1 0 0 0 1 10 28 -1 -"Skateboard with Black Wheels (Shortcut)" "42511c01.DAT" 0 1 0 0 0 1 0 0 0 1 0 28 1 -"Snowshoe" "30284.DAT" 0 1 0 0 0 1 0 0 0 1 10 28 -1 -"Ski" "6120.dat" 0 1 0 0 0 1 0 0 0 1 10 28 1 - -; Update 2015-01 -"Ski 4L without Hinge" "99774.DAT" 0 1 0 0 0 1 0 0 0 1 10 28 -1 - -"Ski 6L" "90509.DAT" 0 1 0 0 0 1 0 0 0 1 10 28 -1 -"--------------------Non-standard accessories------------------------------------" "" 0 1 0 0 0 1 0 0 0 1 0 0 0 -"Plate 2x4 with Curved Beveled Sides" "88000.DAT" 0 1 0 0 0 1 0 0 0 1 0 28 0 -"Surf Board 2 x 6.5" "90397.DAT" 0 0 0 -1 0 1 0 1 0 0 0 28 -1 -"Surf Board 2 x 6.5 with Pink Flames Pattern" "90397P02.DAT" 0 0 0 -1 0 1 0 1 0 0 0 28 -1 -"Surf Board 2 x 10" "6075.DAT" 0 -1 0 0 0 1 0 0 0 -1 0 28 -1 +; Version 2015-02 + +[HATS] +"Cap Aviator" "30171.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Cap Aviator with Black Goggles" "30171C01.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Cap with Long Flat Peak" "4485.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Cap with Short Arched Peak" "86035.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Cap with Short Arched Peak with Seams" "11303.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Cap with Short Arched Peak and Black Headphones" "11303C01.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Castle Helmet with Chin-Guard" "3896.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Castle Helmet with Neck Protector" "3844.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Construction Helmet" "3833.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Cook's Hat" "3898.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Fire Helmet" "3834.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Fire Helmet Breathing Hose" "6158.DAT" 0 1 0 0 0 1 0 0 0 1 0 24 0 +"Fire Helmet with Fire Logo Shield Pattern" "3834p01.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Forestman Cap" "4506.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Forestman Cap with Small Red Plume (Complete)" "4506C01.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Friends Hair Long Straight" "92255.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Friends Hair Long Wavy" "92256.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Friends Hair Long Wavy Partially Tied Back" "92258.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Friends Hair Long with Curls" "93352.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Friends Hair Long w. Ponytail French Braided w. 3 Holes" "15675.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Friends Hair Long w. Ponytail and Side Bangs" "92257.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Friends Hair Long w. Ponytail, Side Bangs a. Riding Helmet" "92254.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Friends Hair Long w. Ponytail, Side Bangs a. BL Riding Helmet""92254P01.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Friends Hair Long w. Ponytail, Side Bangs a. Sun Visor" "15284.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Friends Hair Long w. Ponytail, Side Bangs a. Dk Pink Sun Visor""15284P01.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Friends Hair Short, Bob Cut" "92259.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Friends Hair Wavy w. Curls and 2 Pinholes" "15677.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Friends Hair w. Top Knot Bun and Hair Band" "15673.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Friends Hair w. Top Knot Bun and Medium Blue Hair Band" "15673P01.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Ghost Shroud" "2588.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Hair Backslick" "64798.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Hair Bubble Style (Afro)" "87995.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Hair Combed Front to Rear" "92081.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Hair Female with Pigtails" "3625.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Hair Flat Top" "30608.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Hair Islander" "6025.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Hair Male" "3901.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Hair Long and Half Braided" "30475.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Hair Long Straight" "40239.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Hair Long with French Braid" "59363.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Hair Long with Headband" "30114.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Hair Long with Headband and Feathers (Complete)" "30114C01.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Hair Long with One Front Lock" "85974.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Hair Long Wavy" "40251.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 + +; Update 2015-01 +"Hair Orc with Dark Tan Ears Pattern" "10066P01.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Hair Orc with Ears" "10066.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Hair Orc with Medium Dark Flesh Ears Pattern" "10066P02.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Hair Orc with Olive Green Ears Pattern" "10066P03.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 + +"Hair Peaked" "42444.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Hair Ponytail" "6093a.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Hair Ponytail with Long Bangs" "62696.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Hair Pulled Back" "92756.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Hair Short Tousled" "40233.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Hair Short, Tousled with Side Parting" "62810.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Hair Shoulder Length" "4530.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Hair Spiky Long" "53982.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Hair Spiky Short" "53981.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Hair Straight Cut with Short Ponytail" "17630.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Hair Swept Back Into Bun" "99240.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Hair Swept Back Tousled" "61183.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Hair Swept Right with Front Curl" "98726.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Hair Tousled" "10048.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Hair Wavy" "43751.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 + +; Update 2015-01 +"Hair with Snakes" "12889.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 + +"Hair with Two Buns" "30409.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Hair with Two Locks on Left Side" "15443.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Hat Bicorne" "2528.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Hat Bicorne with Evil Skull and Crossbones Pattern" "2528P30.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Hat Bowler" "95674.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Hat Bowler with Red Flower with Yellow Centre Pattern" "95674P01.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Hat Conical Asian" "93059.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Hat Cowboy" "3629.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Hat Cowboy with Cavalry Logo Pattern" "3629PW1.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Hat Cowboy with Silver Star Pattern" "3629PW2.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Hat Crown" "71015.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Hat Elf with Pointy Ears" "13787.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Hat Elf with Pointy Ears with Bright Green Top Pattern" "13787P01.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Hat Fedora" "61506.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Hat Fez" "85975.dat" 0 1 0 0 0 1 0 0 0 1 0 -14 0 +"Hat Imperial Guard Shako" "2545.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Hat High Cone Shaped" "2338.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Hat Kepi" "30135.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Hat Knit Cap" "41334.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Hat Pith Helmet" "30172.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Hat Rag" "2543.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Hat Tricorne" "2544.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Hat Tricorne with Plume (Complete)" "2544C01.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Hat Wide Brim Flat" "30167.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Hat with Wide Brim Down" "13788.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Headdress Aztec Bird" "99243.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Headdress Aztec Bird with Eyes and Cheeks Pattern" "99243P01.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Headdress Batman" "55704.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Headdress Catwoman" "98729.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Headdress Horus" "93249.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Headdress Horus with Eye Pattern" "93249PQ0.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Headdress Nemes Type 1" "30168.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Headdress Nemes Type 2" "90462.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Headdress Nemes with 2 Darkblue Snakes Pattern" "90462PQ0.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Headdress Nemes with Darkblue Stripes Pattern" "90462PQ1.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Headdress SW Zabrak Horns" "92761.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Headdress Turban" "40235.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Headdress Werewolf" "42443.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Helmet Army" "87998.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Helmet Army with White Stencil Cross Pattern" "87998p01.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Helmet Alien Skull with Fangs" "85945.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Helmet Cap" "60748.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Helmet Cap with Wings" "60747.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Helmet Castle Rohan w. Cheek Protection & Comb" "10054.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Helmet Castle Rohan w. Cheek Prot. & Comb w. Eomer Pat." "10054P01.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Helmet Castle Rohan w. Cheek Prot. & Comb w. Theoden Pat." "10054P02.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Helmet Castle Uruk-Hai with Lateral Comb" "10051.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Helmet Castle Uruk-Hai with Lateral Comb & Hand Pattern" "10051P01.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Helmet Castle with Dragon Crown Top" "6122.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Helmet Castle with Angled Cheek Protection" "48493.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Helmet Castle w. Dragon Crown Top Black w. Dragon Plume" "6122c01.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Helmet Castle w. Dragon Crown Top w. Cattlehorn White" "6122c02.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Helmet Castle with Fixed Face Grille" "4503.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Helmet Classic with Thin Chin Guard" "3842a.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Helmet Classic with Thick Chin Guard" "3842b.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Helmet Darth Vader" "30368.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Helmet Gladiator" "95676.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Helmet Imperial AT-ST Pilot" "57900.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Helmet Iron Man" "10907.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Helmet Iron Man w. Visor w. Gold Face, White Eyes Pattern" "10907C01.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Helmet Modern" "2446.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Helmet Modern with Black, Blue and Silver Unitron Pattern" "2446P51.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Helmet Modern with Blue and Silver Spyrius Pattern" "2446P50.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Helmet Modern with One Red and Two Green Stripes Pattern" "2446P01.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Helmet Morion" "30048.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Helmet Persian" "88284.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Helmet Samurai" "30175.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Helmet Samurai with Horn (Shortcut)" "30175c01.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Helmet Scout Trooper" "30369.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Helmet Skateboard" "46303.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Helmet Stormtrooper" "30408.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Helmet Stormtrooper with Stormtrooper Pattern" "30408p01.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Helmet Stormtrooper with TIE-Fighter Pilot Pattern" "30408p02.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Helmet SW Rebel Pilot" "30370.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Helmet SW Rebel Pilot with Blue Rebel Logo Pattern" "30370ps3.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Helmet SW Rebel Pilot with Checkered Pattern" "30370ps4.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Helmet SW Rebel Pilot with Red Rebel Logo Pattern" "30370ps2.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Helmet SW Rebel Pilot with Yellow Grid on Bley Pattern" "30370ps1.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Helmet SW Rebel Pilot with Yellow Grid on Grey Pattern" "30370ps5.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Helmet Viking with Horns" "53450C01.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Helmet Viking with Nose Protector" "53450.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Helmet with Bat Wings" "30105.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Helmet with Chinstrap and Wide Brim" "30273.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Helmet with Front Prongs" "10305.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Helmet with Front Prongs w. Dark Purple Highlight Pattern" "10305P01.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Helmet with Hexagonal Top, Hoses" "30120.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Helmet with Hexagonal Top, Hoses, Gold Alien Pattern" "30120P01.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Helmet with Hexagonal Top, Hoses, Silver Alien Pattern" "30120P02.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Hood" "30381.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Hood Medieval Cowl" "4505a.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Jester's Cap" "62537.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Jester's Cap with Black Half and White Poms Pattern" "62537p02.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Jester's Cap with Blue Half and Blue Pom Pattern" "62537p01.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Jester's Cap with Red Half and Red Pom Pattern" "62537p03.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Mask Wolf" "11233.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Mask Wolf with Fangs, Scars and White Ears Pattern" "11233P01.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Police Hat" "3624.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Police Helmet" "13789.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Police Helmet with Silver Badge Pattern" "13789P01.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Top Hat" "3878.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Wizards Hat" "6131.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"--------------------------------------------------------------------------------" "" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"None" "" 0 1 0 0 0 1 0 0 0 1 0 0 0 + + + +[HATS2] +"None" "" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Cap Aviator Goggles" "30170.DAT" 0 1 0 0 0 1 0 0 0 1 0 8 0 +"Cattlehorns (repositioning may needed)" "87695.DAT" 0 1 0 0 0 1 0 0 0 1 0 -6 -18 +"Diver Mask" "30090.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 + +; Update 2015-01 +"Feathered Headdress Small" "87696.DAT" 0 1 0 0 0 1 0 0 0 1 0 -12 0 + +"Feathers with Pin" "30126.DAT" 0 1 0 0 0 1 0 0 0 1 0 3.83 17.76 +"Feathers with Pin and Black Tip Pattern" "30126p01.DAT" 0 1 0 0 0 1 0 0 0 1 0 3.83 17.76 +"Friends Glasses Heart Shaped with Pin" "96486.DAT" 0 1 0 0 0 1 0 0 0 1 0 -12 0 +"Friends Glasses Oval Shaped with Pin" "96490.DAT" 0 1 0 0 0 1 0 0 0 1 0 -12 0 +"Friends Hair Decoration Bow with Pin" "96479.DAT" 0 -1 0 0 0 1 0 0 0 -1 0 -12 0 +"Friends Hair Decoration Butterfly with Pin" "96481.DAT" 0 -1 0 0 0 1 0 0 0 -1 0 -12 0 +"Friends Hair Decoration, Bow w. Heart, Long Ribbon w. Pin" "11618.DAT" 0 -1 0 0 0 1 0 0 0 -1 0 -12 0 +"Friends Hair Decoration, Heart with Pin" "96485.DAT" 0 -1 0 0 0 1 0 0 0 -1 0 -12 0 +"Friends Hair Decoration, Star with Pin" "96489.DAT" 0 1 0 0 0 1 0 0 0 1 0 -12 0 +"Headphones / Ear Protection" "14045.DAT" 0 1 0 0 0 1 0 0 0 1 0 -11 0 +"Helmet Samurai Horn (repositioning may needed)" "529.DAT" 0 1 0 0 0 1 0 0 0 1 0 -6 -18 +"Helmet Visor" "2447.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Helmet Visor Ice Planet" "6119.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Helmet Visor Iron Man" "10908.DAT" 0 1 0 0 0 1 0 0 0 1 0 -8 -8 +"Helmet Visor Iron Man w. Gold Face, Blue Eyes Pattern" "10908P02.DAT" 0 1 0 0 0 1 0 0 0 1 0 -8 -8 +"Helmet Visor Iron Man w. Gold Face, White Eyes Pattern" "10908P01.DAT" 0 1 0 0 0 1 0 0 0 1 0 -8 -8 +"Helmet Visor Iron Man w. Silver Face, DkRed Line Pattern" "10908P04.DAT" 0 1 0 0 0 1 0 0 0 1 0 -8 -8 +"Helmet Visor Iron Man w. Silver Face, White Eyes Pattern" "10908P03.DAT" 0 1 0 0 0 1 0 0 0 1 0 -8 -8 +"Helmet Visor Space" "23318.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Helmet Visor Underwater" "6090.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Plume Dragon (repositioning may needed)" "87687.DAT" 0 1 0 0 0 1 0 0 0 1 0 -12 7 +"Plume Large (repositioning may needed)" "87694.DAT" 0 1 0 0 0 1 0 0 0 1 0 -12 7 +"Plume Small (repositioning may needed)" "87693.DAT" 0 1 0 0 0 1 0 0 0 1 0 -12 7 +"Plume Triple (repositioning may needed)" "87692.DAT" 0 1 0 0 0 1 0 0 0 1 0 -12 7 +"Plume/Flame Triple (repositioning may needed)" "64647.DAT" 0 1 0 0 0 1 0 0 0 1 0 -12 7 + + + +[HEAD] +"Stud Solid" "3626A.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Stud Solid with Standard Grin Pattern" "3626AP01.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Standard Grin Pattern" "3626BP01.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Adventurers Mummy Pattern" "3626BPA2.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Beard Stubble, Eyebrows, Smile, Scar Pattern" "3626CPQ0.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Beard, Happy/Angry Pattern (front)" "3626CPBB.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Beard, Happy/Angry Pattern (rear)" "3626CPBB.DAT" 0 -1 0 0 0 1 0 0 0 -1 0 0 0 +"Beard, Sneering/Scared Pattern (front)" "3626CPBH.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Beard, Sneering/Scared Pattern (rear)" "3626CPBH.DAT" 0 -1 0 0 0 1 0 0 0 -1 0 0 0 +"Black Eyebrows and Cheek Lines Pattern (front)" "3626CPB9.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Black Eyebrows and Cheek Lines Pattern (rear)" "3626CPB9.DAT" 0 -1 0 0 0 1 0 0 0 -1 0 0 0 +"Black Mask, Blue Eyes and Black Lips Pattern" "3626BPBA.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Black Moustache, Beard and Messy Hair Pattern" "3626BP44.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Blue Headband and Dark Orange Hair Pattern" "3626BP66.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Blue Sunglasses Pattern" "3626bp7b.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 + +; Update 2015-01 +"Blue Sunglasses and Stubble Pattern" "3626BP7E.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 + +"Blue Wrap-Around Sunglasses Pattern" "3626bp7c.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Big Eyes, Curved Eyebrows, Orange Mouth Pattern" "3626BPAO.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 + +; Update 2015-01 +"Brown Bushy Moustache, Eyebrows, Black Chin Strap Pattern" "3626CPCBE.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 + +"Brown Eyebrows, Smirking Face, Pupils Pattern" "3626BP83.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Brown Hair over Eye and Black Eyebrows Pattern" "3626BP7A.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Brown Hair, Eyelashes, and Lipstick Pattern" "3626BPA6.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Brown Moustache, Stubble, Eyebrows, Frowning Pattern" "3626BP3R.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Dark Grey Facial Hair Pattern" "3626BP39.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Dark Orange Moustache, Beard and Messy Hair Pattern" "3626BP42.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"DkRed Lips, Open/Closed Mouth, Freckles Pattern (front)" "3626CPBJ.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"DkRed Lips, Open/Closed Mouth, Freckles Pattern (rear)" "3626CPBJ.DAT" 0 -1 0 0 0 1 0 0 0 -1 0 0 0 +"DkRed Lips, Smirk/Eyemask Pattern (front)" "3626BPB8.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"DkRed Lips, Smirk/Eyemask Pattern (rear)" "3626BPB8.DAT" 0 -1 0 0 0 1 0 0 0 -1 0 0 0 +"Eye Patch, Black Stubble and Messy Hair Pattern" "3626BP49.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Eye Patch, DkOrange Moustache, Beard a. Messy Hair Pattern""3626BP46.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Eye Patch, DkOrange Stubble and Messy Hair Pattern" "3626BP48.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Eye Patch, Red Moustache, Beard and Messy Hair Pattern" "3626BP47.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Eyeglasses and Lightning Scar Pattern" "3626BPH1.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Eyes in Mask, White 'A' and Black Line on Back Pattern" "3626CPBL.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Evil Skeleton Skull Pattern" "3626BPA8.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 + +; Update 2015-01 +"Female with Lopsided Smile/Determined Pattern (front)" "3626CP8D.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Female with Lopsided Smile/Determined Pattern (rear)" "3626CP8D.DAT" 0 -1 0 0 0 1 0 0 0 -1 0 0 0 + +"Female with Brown Eyebrows, Pupils, Eyelashes Pattern" "3626BP09.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Female with Red Lips Small Eyebrows Pattern" "3626BP08.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Female with Smiling/Scared Pattern (front)" "3626BPQ3.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Female with Smiling/Scared Pattern (rear)" "3626BPQ3.DAT" 0 -1 0 0 0 1 0 0 0 -1 0 0 0 +"Freckle Nose and Standard Grin Pattern" "3626bp07.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Glasses and White Muttonchops Pattern" "3626BPA1.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Glasses, Brown Sideburns and Moustache Pattern" "3626BPQ4.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Glasses, Grey Eyes, Eyebrows, Cheeks Pattern" "3626CPBK.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Glasses, Thin Brown Eyebrows, Smile Pattern" "3626BP87.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Gold Paint and Slanted Eyes Pattern" "3626BP6U.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Gold Robot Pattern" "3626BP64.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Green Brain and Yellow Mouth Pattern" "3626BP6Y.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Green Lips and Red Eyebrows Pattern" "3626BPB5.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Gregory Goyle/Harry Potter Pattern (front)" "3626BPH4.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Gregory Goyle/Harry Potter Pattern (rear)" "3626BPH4.DAT" 0 -1 0 0 0 1 0 0 0 -1 0 0 0 +"Grey Hair, Beard, Moustache, Angry Pattern" "3626BP0A.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Grumpy/Angry Pattern (front)" "3626CPBD.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Grumpy/Angry Pattern (rear)" "3626CPBD.DAT" 0 -1 0 0 0 1 0 0 0 -1 0 0 0 +"Half-Moon Glasses and Grey Eyebrows Pattern" "3626BPHA.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Headset Over Brown Hair & Eyebrows Pattern" "3626BP69.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Ice Planet Female Red Hair Pattern" "3626BP65.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Ice Planet Messy White Hair Pattern" "3626BP62.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Ice Planet Moustache and Eyebrows Pattern" "3626BP61.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Islander White/Blue Painted Face Pattern" "3626BP3K.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Islander White/Red Painted Face Pattern" "3626BP3J.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Large Blue Mask Pattern" "3626BP6V.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Lefty Mouth and Stubble Pattern" "3626BP81.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"LOTR Brown Eyebrows Worried/Smile Pattern (front)" "3626CPM2.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"LOTR Brown Eyebrows Worried/Smile Pattern (rear)" "3626CPM2.DAT" 0 -1 0 0 0 1 0 0 0 -1 0 0 0 +"LOTR DkBrown Beard, Stubble and Stern Pattern (front)" "3626CPM7.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"LOTR DkBrown Beard, Clenched Teeth Pattern (rear)" "3626CPM7.DAT" 0 -1 0 0 0 1 0 0 0 -1 0 0 0 +"LOTR Frowning/Grimacing Pattern (front)" "3626CPM6.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"LOTR Frowning/Grimacing Pattern (rear)" "3626CPM6.DAT" 0 -1 0 0 0 1 0 0 0 -1 0 0 0 +"LOTR Frowning/Scared Pattern (front)" "3626CPM4.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"LOTR Frowning/Scared Pattern (rear)" "3626CPM4.DAT" 0 -1 0 0 0 1 0 0 0 -1 0 0 0 +"LOTR Frowning/Shouting Pattern (front)" "3626CPM5.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"LOTR Frowning/Shouting Pattern (rear)" "3626CPM5.DAT" 0 -1 0 0 0 1 0 0 0 -1 0 0 0 +"LOTR Orc with Grey Hair Pattern" "3626BPMA.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"LOTR Smirking/Shouting Pattern (front)" "3626CPM8.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"LOTR Smirking/Shouting Pattern (rear)" "3626CPM8.DAT" 0 -1 0 0 0 1 0 0 0 -1 0 0 0 +"LOTR Thick Gray Eyebrows and Smile Pattern" "3626CPM1.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"LOTR Tired/Poisoned Pattern (front)" "3626CPM3.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"LOTR Tired/Poisoned Pattern (rear)" "3626CPM3.DAT" 0 -1 0 0 0 1 0 0 0 -1 0 0 0 +"LOTR Uruk-Hai Lurtz Scowl and White Hand Pattern (front)" "3626BPMB.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"LOTR Uruk-Hai Lurtz Scowl and White Hand Pattern (rear)" "3626BPMB.DAT" 0 -1 0 0 0 1 0 0 0 -1 0 0 0 +"LOTR Uruk-Hai Scowl and White Hand Pattern (front)" "3626CPM0.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"LOTR Uruk-Hai Scowl and White Hand Pattern (rear)" "3626CPM0.DAT" 0 -1 0 0 0 1 0 0 0 -1 0 0 0 +"Mask Br.Green with Eyeholes and Smile Pattern" "3626BPB2.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Mask Purple with Eyeholes and Smile Pattern" "3626BPB6.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Messy Hair and Eye Patch Pattern" "3626BP31.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Messy Hair and Moustache Pattern" "3626BP30.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Messy Hair Female Pattern" "3626BP40.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Messy Hair, Beard and Eye Patch Pattern" "3626BP34.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Messy Hair, Moustache and Beard Pattern" "3626BP33.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Messy Hair, Moustache and Eye Patch Pattern" "3626BP32.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Messy Hair, Moustache and Stubble Pattern" "3626BP35.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Monocle and Black Slanted Eyebrows Pattern" "3626bpb7.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Monocle, Scar, and Moustache Pattern" "3626BPA7.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Mummy Face with 2 Eyes / 1 Eye Pattern (front)" "3626BPQ0.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Mummy Face with 2 Eyes / 1 Eye Pattern (rear)" "3626BPQ0.DAT" 0 -1 0 0 0 1 0 0 0 -1 0 0 0 +"Mummy with 2 Eyes / Gold Death Mask Pattern (front)" "3626BPQ1.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Mummy with 2 Eyes / Gold Death Mask Pattern (rear)" "3626BPQ1.DAT" 0 -1 0 0 0 1 0 0 0 -1 0 0 0 +"Open Smiling Mouth, Teeth and Tounge Pattern" "3626BPC44.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Orange Beard and White Smile Pattern" "3626BP80.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Peach Lips, Smile, Black Eyebrows Pattern" "3626BP8C.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Peach Lips, Smile, Black Eyebrows Pattern (Hollow Stud)" "3626CP8C.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Pursed Lips and White Forehead Pattern" "3626BPB1.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Red Lips and Black Upswept Eyelashes Pattern" "3626bp6f.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Red Moustache, Beard and Messy Hair Pattern" "3626BP43.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Ron Weasley Pattern" "3626bph3.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Severus Snape Pattern" "3626BPHB.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Sideburns and Droopy Moustache Black Pattern" "3626BP3N.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Sideburns and Droopy Moustache Brown Pattern" "3626BP3Q.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Sideburns, Goatee, Beard Stubble, Scar Pattern" "3626BPQ2.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Silver Mask and Mouth Grille Pattern" "3626BP6X.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Silver Robot Pattern" "3626BP63.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Silver Sunglasses and Red Headset Pattern" "3626BP68.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Skull Cracked with Metal Plates Pattern" "3626CPN2.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Skull Type 1 (Happy) Pattern" "82359.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Small Blue Mask Pattern" "3626BP6W.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Smile and Gold Tooth Pattern" "3626BP86.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Smile, Black Eyebrows and White Pupils Pattern" "3626BP84.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Smile, Brown Eyebrows and White Pupils Pattern" "3626BP85.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Smirk, Black Moustache Pattern" "3626BPA3.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Smirk, Black Hair and Goatee Pattern" "3626BP82.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Standard Grin and Eyebrows Pattern" "3626BP05.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Standard Grin and Pointed Moustache Pattern" "3626BP03.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Standard Grin and Sunglasses Pattern" "3626BP04.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Standard Grin, Eyebrows and Microphone Pattern" "3626BP06.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Standard Woman Pattern" "3626BP02.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Stubble, Moustache and Smirk Pattern" "3626BPA5.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"SW Alien with Large Black Eyes Pattern" "3626BPSB.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"SW Black Eyebrows and Scars Pattern" "3626BPS7.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"SW Brown Eyebrows and Beard Pattern" "3626BPS9.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"SW Brown Eyebrows Pattern" "3626BPS2.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"SW Darth Maul Pattern" "3626BPS8.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"SW Freckles and Thin Brown Eyebrows Pattern" "3626BPSD.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"SW Grey Beard and Eyebrows Pattern" "3626BPS4.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"SW Grey Eyebrows & Implant Pattern (front)" "3626BPSC.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"SW Grey Eyebrows & Implant Pattern (rear)" "3626BPSC.DAT" 0 -1 0 0 0 1 0 0 0 -1 0 0 0 +"SW Jawa, Yellow Eyes with Orange Rim Pattern" "3626CPS0.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"SW Red Lips, Black Eyes, Thin Eyebrows Pattern" "3626BPS0.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"SW Scout Trooper Black Visor Pattern" "3626BPSE.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"SW Small Black Eyebrows Pattern" "3626BPS3.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"SW Smirk and Brown Eyebrows Pattern" "3626BPS5.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"SW Tusken Raider Pattern" "3626BPST.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Tan Eyebrows and Frown Pattern" "3626BPH2.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Teeth, Pupils, Brown Eyebrows Pattern" "3626BP0B.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Thin Moustache, Stubble and Sideburns Pattern" "3626BP67.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Tribal Paint and Frown Pattern" "3626BPAC.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Uruk-Hai Scowl and White Hand Pattern (front)" "3626BPM0.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Uruk-Hai Scowl and White Hand Pattern (rear)" "3626BPM0.DAT" 0 -1 0 0 0 1 0 0 0 -1 0 0 0 +"Villian Black Facial Hair Pattern" "3626BPA4.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Villainous Glasses & Black Facial Hair Pattern" "3626bpa9.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Vincent Crabbe/Ron Weasley Pattern" "3626bph5.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"White Hair, Eyebrows, and Moustache Pattern" "3626BPN1.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Wide Smile, Red Lips and Crow's Feet Pattern" "3626BPB3.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Wiry Moustache, Goatee and Eyebrows Pattern" "3626bp3e.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"--------------------Non-standard heads------------------------------------------" "" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Alien Squidman" "85947.DAT" 0 1 0 0 0 1 0 0 0 1 0 24 0 +"Alien Squidman with Black Eyes & Lines Pattern" "85947P01.DAT" 0 1 0 0 0 1 0 0 0 1 0 24 0 +"Anubis Guard" "93248.DAT" 0 1 0 0 0 1 0 0 0 1 0 24 0 +"Anubis Guard with Gold Eye and Stripes Pattern" "93248PQ0.DAT" 0 1 0 0 0 1 0 0 0 1 0 24 0 +"Elf" "43745.DAT" 0 1 0 0 0 1 0 0 0 1 0 24 0 +"Elf with Green Eyes Pattern" "43745P01.DAT" 0 1 0 0 0 1 0 0 0 1 0 24 0 +"Ewok" "64805.DAT" 0 1 0 0 0 1 0 0 0 1 0 24 0 +"Goblin" "42109.DAT" 0 1 0 0 0 1 0 0 0 1 0 24 0 +"Martian Head with Clip" "30529.DAT" 0 1 0 0 0 1 0 0 0 1 0 32 0 +"Martian Head with Clip with Eyes Plain Pattern" "30529P01.DAT" 0 1 0 0 0 1 0 0 0 1 0 32 0 +"Martian Head with Clip with Eyelashes Pattern" "30529P02.DAT" 0 1 0 0 0 1 0 0 0 1 0 32 0 +"Mechanical Head SW Battle Droid" "30378.DAT" 0 1 0 0 0 1 0 0 0 1 0 32 0 +"Nautolan" "57901.DAT" 0 1 0 0 0 1 0 0 0 1 0 24 0 +"Nautolan, Black Eyes & Mouth, Brown Tentacle Bands" "57901P01.DAT" 0 1 0 0 0 1 0 0 0 1 0 24 0 +"Protocol Droid" "30480.DAT" 0 1 0 0 0 1 0 0 0 1 0 24 0 +"Protocol Droid with Light Yellow Eyes Pattern" "30480PS0.DAT" 0 1 0 0 0 1 0 0 0 1 0 24 0 +"Robot" "98384.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Robot with Blue Eyes and Red/yellow Teeth Display" "98384P01.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Rodian without Pattern" "47545.DAT" 0 1 0 0 0 1 0 0 0 1 0 24 0 +"Rodian with Eyes and Nose Pattern" "47545P01.DAT" 0 1 0 0 0 1 0 0 0 1 0 24 0 +"Simpsons Bart Simpson" "15523.DAT" 0 1 0 0 0 1 0 0 0 1 0 24 0 +"Simpsons Bart Simpson with Eyes Looking Left Pattern" "15523P01.DAT" 0 1 0 0 0 1 0 0 0 1 0 24 0 +"Simpsons Bart Simpson with Eyes Pattern" "15523P02.DAT" 0 1 0 0 0 1 0 0 0 1 0 24 0 +"Simpsons Homer Simpson" "15527.DAT" 0 1 0 0 0 1 0 0 0 1 0 24 0 +"Simpsons Homer Simpson with Half Closed Eyes Pattern" "15527P01.DAT" 0 1 0 0 0 1 0 0 0 1 0 24 0 +"Simpsons Homer Simpson with Wide Open Eyes Pattern" "15527P02.DAT" 0 1 0 0 0 1 0 0 0 1 0 24 0 +"Simpsons Lisa Simpson" "15524.DAT" 0 1 0 0 0 1 0 0 0 1 0 24 0 +"Simpsons Lisa Simpson with Eyes Pattern" "15524P02.DAT" 0 1 0 0 0 1 0 0 0 1 0 24 0 +"Simpsons Lisa Simpson with Worried Eyes Pattern" "15524P01.DAT" 0 1 0 0 0 1 0 0 0 1 0 24 0 +"Simpsons Marge Simpson" "15522.DAT" 0 1 0 0 0 1 0 0 0 1 0 24 0 +"Simpsons Marge Simpson with Eyes Looking Right Pattern" "15522P01.DAT" 0 1 0 0 0 1 0 0 0 1 0 24 0 +"Simpsons Marge Simpson with Wide Open Eyes Pattern" "15522P02.DAT" 0 1 0 0 0 1 0 0 0 1 0 24 0 + +; Update 2015-01 +"Simpsons Ned Flanders" "15529.DAT" 0 1 0 0 0 1 0 0 0 1 0 24 0 +"Simpsons Ned Flanders w. Glasses, Hair, Moustache Pattern" "15529P01.DAT" 0 1 0 0 0 1 0 0 0 1 0 24 0 + + +"SpongeBob" "54872.DAT" 0 1 0 0 0 1 0 0 0 1 0 8 0 +"SpongeBob with Happy Pattern" "54872p01.DAT" 0 1 0 0 0 1 0 0 0 1 0 8 0 +"SpongeBob with Shocked Pattern" "54872P02.DAT" 0 1 0 0 0 1 0 0 0 1 0 8 0 +"SpongeBob with Super Hero Pattern" "54872P09.DAT" 0 1 0 0 0 1 0 0 0 1 0 8 0 +"Spongebob Octopus" "64767.DAT" 0 1 0 0 0 1 0 0 0 1 0 24 0 +"Spongebob Starfish" "54873.DAT" 0 1 0 0 0 1 0 0 0 1 0 24 0 +"Stud Hollow" "3626B.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Wookiee with Bandolier" "30483.DAT" 0 1 0 0 0 1 0 0 0 1 0 24 0 +"Wookiee with Silver Bandolier/Black Nose Pattern" "30483P01.DAT" 0 1 0 0 0 1 0 0 0 1 0 24 0 +"Yoda with Curved Ears" "41880.DAT" 0 1 0 0 0 1 0 0 0 1 0 24 0 +"--------------------------------------------------------------------------------" "" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"None" "" 0 1 0 0 0 1 0 0 0 1 0 0 0 + + + +[BODY] +"Plain" "973.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"#1 Racing Pattern" "973P80.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"'S' Logo Grey / Blue Pattern" "973P23.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"'S' Logo Red / Black Pattern" "973P14.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"'Tine' Sticker" "973D01.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"2 Chinese Letters Yellow Stripe Pattern" "973PAQ.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"3-Piece Suit, White Shirt and Red Tie Pattern" "973PDB.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Air Gauge and Pocket Pattern" "973P29.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Airplane Logo and 'AIR' Badge Pattern" "973P85.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Airplane Logo Pattern" "973P16.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Anchor Motif Pattern" "973P09.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Arctic Parka 'A1' Pattern" "973P7A.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Arctic Parka 'A2' Pattern" "973P7B.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Armor Vest, Silver Wolf Head and Blue Round Jewel Pattern" "973PAW.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Astro Pattern" "973P6F.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Autoroute Pattern" "973P27.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Aviator Jacket w. Eagle/'SMH' on Back Pattern" "973PQ5.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Bandage and Gold Necklace Pattern" "973PQ0.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Bandage, Gold Necklace and Gold Belt Pattern" "973PQ1.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Batman Robin Pattern" "973Pb2.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Black Collar and Pockets Pattern" "973pst.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Black Diagonal Zip and Pocket Pattern" "973p0b.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Black Dungaree Pattern" "973P1A.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Black Falcon Pattern" "973P43.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Black Futuron Pattern" "973P6B.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Black Half Pattern" "973PBM.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Blacktron I Pattern" "973P52.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Blacktron II Pattern" "973P51.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Blouse, Belt and Necklace Pattern" "973PQ6.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Blue and Mint Green Stripes Pattern" "973p2e.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Blue Castle Bodice Pattern" "973P4N.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Blue Dungaree Pattern" "973P1B.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Blue Futuron Pattern" "973P6C.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Blue Flowers on Tied Shirt Pattern" "973P2G.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Blue Horizontal Stripes Pattern" "973p1d.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Blue Imperial Guard Officer Pattern" "973P3R.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Blue Imperial Guard Pattern" "973P3N.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Blue Plaid Shirt" "973PDD.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Blue Shirt and Safety Stripes Pattern" "973P8G.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Blue Striped Dungarees Pattern" "973P1R.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Blue Undershirt Green Bow and Gun Pattern" "973PW5.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Blue Vest, Collar and Star Pattern" "973PAR.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Blue Vest, Collar and Test Tube Pattern" "973PAS.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Blue Vest, Pockets, Shirt and Drill Pattern" "973PAT.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Blue Vest, Tools, Shirt and Bomb Pattern" "973PAU.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Bomber Jacket & Black Shirt Pattern" "973P70.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Bomber Jacket, Belt, & Black Shirt Pattern" "973PA5.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Brown Vest, Ascot and Belt Pattern" "973P3B.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Brown Vest, Buckle and String Bowtie Pattern" "973PW9.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 + +; Update 2015-01 +"Business Suit and Tie, Breathing Apparatus, Octan Pattern" "973P6H.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 + +"Buttons and Police Badge Plain Pattern" "973P1F.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Card, Suit, Vest, and Gold Fob Pattern" "973PW8.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Castle Breastplate Pattern" "973P40.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Castle Bodice and Cloak Pattern" "973P4H.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Castle Chainmail Pattern" "973P41.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Castle Crossed Pikes Pattern" "973P42.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Castle Female Armour Pattern" "973P4G.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Castle Red/Gray Pattern" "973P47.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Catsuit, Ring Zipper Pull and Belt Pattern" "973PB8.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Chef Pattern" "973p2a.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Classic Space Pattern" "973P90.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 + +; Update 2015-01 +"Classic Space Simulated Wear Pattern" "973P91.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 + +"Clockwork Robot Pattern" "973PC67.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Construction Safety Vest with Reflective Stripes Pattern" "973P8I.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Corset with Reddish Brown Laces Pattern" "973p4w.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Crew Neck Sweater with Bright Pink Collar Pattern" "973PD17.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Crew Neck Sweater w. Collar and 'HAIL TO THE CHEF'Pattern" "973P89.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Crown on DarkBlue/MediumBlue Quarters Pattern" "973p4j.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Dark Orange Vest and Purple Bow Tie Pattern" "973pb7.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"DkBlue Muscles and Gold Necklace Pattern" "973pq2.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"DkGreen Corset with Leather Belt Pattern" "973p4x.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"DkGray, Black, and Yellow Batman Pattern" "973PB1.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Dragon Head Pattern" "973P4B.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Dress and Red Beads Necklace Pattern" "973PD13.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Dress, White Apron and Red Beads Necklace" "973P88.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Explorien Logo Pattern" "973p55.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Extreme Team Jacket Logo Pattern" "973P8A.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Fantasy Era Peasant Rope Belt Pattern" "973p4v.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 + +; Update 2015-01 +"Female Jumpsuit w. Zipper, Markings, Classic Space Pattern""973P6G.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 + +"Female Pirate Pattern" "973P38.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Female Shirt with Two Buttons and Shell Pendant Pattern" "973P8K.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Female White Shirt, Open Jacket Pattern" "973PAE.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Female with Harlequin Black/White Pattern" "973PBA.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Female with Jacket, 2 Pockets, Buttons, Necklace Pattern" "973PBJ.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Female with LtPurple Scarf and Gray Belt Pattern" "973P7Y.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Five Button Fire Fighter Pattern" "973P21.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Forestman and Purse Pattern" "973P46.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Forestman Black Collar Pattern" "973P50.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Forestman Blue Collar Pattern" "973P49.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Forestman Maroon Collar Pattern" "973P48.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Four Button Suit and Train Logo Pattern" "973P84.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Front and Rear Stickers w. 'TINE' Logo on Blue Background" "973D05.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Gold Fob and 100 Dollar Bills Pattern" "973PWA.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Gold Ice Planet Pattern" "973P61.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Gold Lion and Belt on Red/White Quarter Pattern" "973P4L.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Gold Necklace and Yellow Undershirt Pattern" "973P72.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Grey and Gold Batman Pattern" "973pb0.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Grey Muscles and Arc Reactor Pattern" "973PBH.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Green Castle Bodice Pattern" "973P4Q.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Green Dungaree Pattern" "973P1J.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Green Stripes and Leather Strap Pattern" "973P3T.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Gryffindor Uniform Pattern" "973PH1.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Hogwarts Uniform Pattern" "973PH0.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Hooded Sweatshirt/Blue Pocket/Drawstring Pattern" "973p7j.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Horse Head Pattern" "973P2M.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"HP Jacket with 4 Button Vest and Bow Tie Pattern" "973PH4.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"HP with Dark Red Sweater and Yellow Neck Pattern" "973ph8.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"HP with Grey Sweater and Light Flesh Neck Pattern" "973ph7.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"HP with Jacket and Dark Red Sweater Pattern" "973ph6.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"HP with Jacket and Light Grey Sweater Pattern" "973ph5.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Imperial Soldier Pattern" "973P3U.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Insectoids Female, Blue Diamond under Circuits Pattern" "973P58.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Iron Man Armoured Suit Mark VI Pattern" "973PBB.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Iron Man Armoured Suit Mark VII Pattern" "973PBC.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Iron Man Armoured Suit Mark XLII Pattern" "973PBF.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Iron Man Armoured Suit Mark XVII Pattern" "973PBE.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Iron Patriot Armoured Suit Pattern" "973PBG.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Ivy Dress Pattern" "973PB5.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Jacket, Badge and Red Tie Pattern" "973P7R.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Jacket, Bow Tie, Vest, Boutonniere Pattern" "973PC23.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Jacket, Orange Vest, Green Neck-chief Pattern" "973PB3.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Jacket, Pink Shirt, Ring on Necklace Pattern" "973p7h.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Jacket, Pocket, Badge, Blue Tie Pattern" "973P7Q.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Jacket, Tie and Police Badge Yellow Star Pattern" "973p76.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Jacket, White Shirt, and Necklace Pattern" "973PA8.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Jacket over Lt Blue Button Down Shirt Pattern" "973P7Z.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Jacket over Shirt and Prison Stripes Pattern" "973p7t.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Jail Stripes and '23768' Pattern" "973P7K.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Launch Command Logo and Equipment Pattern" "973p1q.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Leather Jacket Pattern" "973P28.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Leather Jacket and Badge Pattern" "973P7U.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Leather Jacket, Badge, 'POLICE' Back Pattern" "973p7n.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Leather Jacket and Light Gray Shirt Pattern" "973PA9.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Lifebelt Logo and ID Card Pattern" "973P79.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Lion Gold on Blue Shield Pattern" "973P4F.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"LOTR Armor, Brown Belt & Gold Buckle Pattern" "973PM5.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"LOTR Button Shirt with Braces Pattern" "973PM2.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"LOTR Coat, DkBluish Grey Shirt, Evenstar Pendant Pattern" "973PM7.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"LOTR Cloak, Rope and Belt Pattern" "973PM1.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"LOTR Cloak with Dark Bluish Grey Folds Pattern" "973PM9.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"LOTR Jacket and Dark Red Vest Pattern" "973PM3.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"LOTR Jacket and Yellow Vest Pattern" "973PM8.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"LOTR Leather Armor with Buckle Pattern" "973PM0.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"LOTR Orc Leather Armor Pattern" "973PMA.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"LOTR Scale Armor and Belt Pattern" "973PM6.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"LOTR Shirt, Dark Brown Belt & Bag Pattern" "973PM4.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"LOTR Uruk-Hai Lurtz Muscles Outline Pattern" "973PMB.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Magenta Questionmark Pattern" "973PB6.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Mail Horn Pattern" "973P1S.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Maroon/Red Quarters Shield Pattern" "973P4U.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Mayan Necklace, Tribal Shirt, & Navel Pattern" "973PAC.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"MBA Level 1 Logo Pattern" "973PT0.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"MBA Level 2 Logo Pattern" "973PT1.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Medallion, Belt and Silver Buttons Pattern" "973p3d.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Modern Firefighter Type 1 Pattern" "973p77.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Modern Firefighter Type 2 Pattern" "973p78.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"MTron Logo Pattern" "973P68.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Necklace and Blue Squares Pattern" "973PWE.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Necklace and Fringe Pattern" "973PC11.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Neon Yellow Stripes, Radio and Badge Pattern" "973P7V.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Ninja Wrap, Gold Shuriken & Armour Pattern" "973PN6.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Ninja Wrap, Gold Shuriken & Dagger Pattern" "973PN7.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Ninja Wrap, Silver Shuriken & Dagger Pattern" "973PN5.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Octan OIL Badge Pattern" "973P81.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Octan Logo Pattern" "973PT2.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Old Obi-Wan Pattern" "973PS6.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 + +; Update 2015-01 +"Open Jacket, Blue Top and Navel Pattern" "973PD1.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 + +"Open Jacket over Striped Vest Pattern" "973P34.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Open Suit Revealing Superman Logo Pattern" "973PBK.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Palm Tree Pattern" "973P2H.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Palm Tree and Dolphin Pattern" "973P2J.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Palm Tree and Horse Pattern" "973P2K.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Patch Pocket Pattern" "973P26.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Pharaoh Breastplate Pattern" "973PA2.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Pinstriped Jacket and Gold Tie Pattern" "973P8L.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Pirate Captain Pattern" "973P36.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Pirate Green Vest, Shirt, and Belt Pattern" "973P3C.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Pirate Open Jacket over Brown Vest Pattern" "973P39.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Pirate Purple Vest and Anchor Tattoo Pattern" "973P30.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Pirate Ragged Shirt and Dagger Pattern" "973P3A.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Pirate Stripes Blue/White Pattern" "973P3E.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Pirate Stripes Blue/Cream Pattern" "973P32.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Pirate Stripes Red/Black Pattern" "973P33.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Pirate Stripes Red/Cream Pattern" "973P31.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Pirate Vest, Anchor Tattoo, Rope on Back Pattern" "973P3V.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Plain Shirt with Pockets Pattern" "973P7G.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Police Jacket, Silver Badge, 4 Buttons and Belt Pattern" "973PCBF.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Prisoner and '50380' Pattern" "973P7S.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Purple Greatcoat Pattern" "973phb.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Racing Jacket and Two Stars Pattern" "973P1H.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Racing Jacket and Two Stars Red Pattern" "973P1N.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Red Cross and Stethoscope Pattern" "973P25.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Red Cross Pattern" "973P24.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Red Dungaree Pattern" "973P1C.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Red Futuron Pattern" "973P6D.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Red Horizontal Stripes Pattern" "973p1E.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Red Imperial Guard Officer Pattern" "973P3S.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Red Imperial Guard Pattern" "973P3Q.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Red Necklace and Blue Undershirt Pattern" "973P71.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Red on Bottom and Fringe Pattern" "973pwd.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Red Shirt and Suit Pattern" "973P22.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Red Truck Pattern" "973P1T.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Red Undershirt and Fringe Pattern" "973PW7.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Red V-Neck and Buttons Pattern" "973P17.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Red Vest and Train Logo Pattern" "973P82.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Red & Gray Shirt, Pot Belly, Jacket Pattern" "973PAF.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Red/Peach Quarters Shield Pattern" "973P4T.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Red/White Waist, Zipper and White Star Pattern" "973pbl.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"RES-Q Orange Pockets and Logo Pattern" "973P8B.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Riding Jacket Pattern" "973P12.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Robot Pattern" "973P63.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Rock Raiders Jet Pattern" "973PAJ.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Royal Knights Lion Head & Neck-Chain Pattern" "973P4E.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Royal Knights Lion-Head Shield Pattern" "973P4D.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Rumpled Shirt, 2 Revolvers in Belt Pattern" "973PAA.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Safari Shirt, Black Tee, and Holster Pattern" "973PA7.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Safari Shirt, Blue Tee & Red Bandana Pattern" "973PA6.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Safari Shirt, Gun & Red Bandana Pattern" "973PA3.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Safari Shirt, Tan Bandana & Compass Pattern" "973PQ7.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Samurai Dragon Robe Pattern" "973PN0.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Samurai Robe, Sash and Dagger Pattern" "973PN1.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Security Guard Pattern" "973PB4.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Shell Logo Pattern" "973P60.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Sheriff Pattern" "973PW4.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Shirt Collar and Sand Green Neck Pattern" "973PX0.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Shirt with Black Belly Bump and Collar Outline Pattern" "973PD11.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Shirt, Badge, Blue Tie, 'POLICE' Back Pattern" "973P7M.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Shirt, Pink/Salmon Tie and ID Badge" "973P87.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Silver Armor Front and Back and Drill Pattern" "973PAV.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Silver Ice Planet Pattern" "973P62.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Six Button Suit and Airplane Pattern" "973p04.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Six Button Suit and Anchor Pattern" "973p05.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 + +; Update 2015-01 +"Skull and DkPink Roses Pattern" "973PC00.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Skull and Red Roses Pattern" "973PC44.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 + +"Slingshot on Back Pattern" "973PD12.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Slytherin Uniform Pattern" "973PH2.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Soccer Shirt '10' and 'ZIDANE' Pattern" "973PG0.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Space Police II and Radio Pattern" "973P69.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Space Police II Chief" "973P6A.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Spotted Singlet and Necklace Pattern" "973p2f.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Spyrius Pattern" "973P66.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Stethoscope and Pocket with Pens Pattern" "973P86.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Sticker Shell Logo on White Background" "973D04.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Straight Zipper Jacket Pattern" "973P13.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Strapless Suntop Pattern" "973P2C.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Striped Shirt and Silver Buttons Pattern" "973P3F.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Studded Armor Pattern" "973P45.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Studios Director Pattern" "973PD0.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Suit and Tie Pattern" "973P18.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Suit and Tie with Train Pattern" "973P83.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Suit with Pocket, Red Tie, Train Pattern" "973P8H.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Superman Logo and Dark Blue Muscles Pattern" "973pb9.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Suspenders and Red Bowtie Pattern" "973PA1.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"SW Belt Pockets and Necklace Blissl Flute Pattern" "973PRG.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"SW Black Vest & White Shirt Pattern" "973PS5.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"SW Blast Armor (Green Plates) Grey Pattern" "973PSB.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"SW Blast Armor (Green Plates) Bl.Grey Pattern" "973PRB.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"SW Blast Armor (Silver Plates) Pattern" "973PSJ.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"SW Blast Armor (Uncolored Plates) Pattern" "973PRC.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"SW Cad Bane Pattern" "973PSW.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"SW Camouflage Smock Pattern" "973PSM.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"SW Closed Shirt and Brown Belt Pattern" "973PR0.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"SW Dark Red Robe Pattern" "973PSX.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"SW Darth Vader Grey Pattern" "973PS7.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"SW Darth Vader Bluish Grey Pattern" "973PRA.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"SW Darth Vader Death Star Pattern" "973PSZ.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"SW Grey Shirt, Belt with Red Buckle Pattern" "973PR7.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"SW Gungan Dark Gray/Dark Tan Shirts Pattern" "973PR6.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"SW Hoth Trooper Pattern" "973PSH.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"SW Imperial Grand Moff Pattern" "973PR9.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"SW Imperial Officer Pattern" "973PSQ.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"SW Imperial Shuttle Pilot Pattern" "973PSN.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"SW Jawa Pattern" "973PSS.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"SW Jawa with Dark Brown Pouches and Black and Tan Straps" "973PRI.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"SW Jedi Robes and Sash Pattern" "973PS2.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"SW Layered Shirt, Brown Belt Pattern" "973PR3.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"SW Layered Shirt, Brown Belt, Braid Pattern" "973PR4.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"SW Layered Shirt, Waist Sash Pattern" "973PS8.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"SW Leia Hoth Jacket Pattern" "973PRD.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"SW Loose Dress Light Bluish Grey Folds Pattern" "973PSY.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"SW Loose Dress Light Grey Folds Pattern" "973PRY.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"SW Moisture Farmer Pattern" "973PSV.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"SW Nute Gunray Pattern" "973PRH.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"SW Pocket-Vest and Techno-Buckle Pattern" "973PSC.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"SW Protocol Droid Pattern" "973psr.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"SW Rebel A-Wing Pilot Pattern" "973PS0.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"SW Rebel Mechanic Pattern" "973PSA.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"SW Rebel Pilot Pattern" "973PS1.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"SW Rebel Pilot Bluish Grey Pattern" "973PR8.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"SW Robe and Rope Belt Pattern" "973PR2.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"SW Robe, Sash and Silver Neck Clasp Pattern" "973PR1.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 + +; Update 2015-01 +"SW Shadow Trooper Pattern" "973PRK.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 + +"SW Scout Trooper Pattern" "973PSE.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"SW Scout Trooper Bluish Grey Pattern" "973PRE.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"SW Shirt (Open Collar, No Vest) Pattern" "973PS4.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"SW Stormtrooper Pattern" "973PSK.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"SW Tank Top Pattern" "973PRF.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"SW Tunic and Belt Pattern" "973PSF.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"SW Vest, White Shirt & Lt Flesh Neck Pattern" "973PR5.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"SW Wrap-Around Tunic Pattern" "973PS3.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Tank Top, Braces & Yellow Skin Pattern" "973PQ4.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Tank Top, Stains, Wrench, and Tattoo Pattern" "973PAB.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Telephone Pattern" "973P8F.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Town Vest with Pockets and Striped Tie Pattern" "973P8J.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Train Chevron Pattern" "973P19.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Tri-Coloured Shield and Gold Trim Pattern" "973p4s.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Tri-Coloured Shield Large Pattern" "973P4R.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"TV Logo Pattern Large Pattern" "973p1m.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"TV Logo Pattern Small Pattern" "973P1K.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"UFO Alien Orange and Silver Pattern" "973P54.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"UFO Alien Triangular Insignia Pattern" "973P6U.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"UFO Alien Yellow Insignia, 3 Blue Bars Pattern" "973P6V.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"UFO Alien Circuitry, Red Level Pattern" "973P6W.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"UFO Silver and Gold Circuitry Pattern" "973P6X.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Unitron Pattern" "973P64.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"US Cavalry General Pattern" "973PW1.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"US Cavalry Officer Pattern" "973PW2.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"US Cavalry Soldier Pattern" "973PW3.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"V-Neck Shirt and Blue Overalls Pattern" "973P7W.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Vertical Red Stripes and 'Clutchers' Pattern" "973PC3G.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Vertical Striped Blue/Red Pattern" "973P02.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Vertical Striped Red/Blue Pattern" "973P01.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Vest with Patch Pockets Pattern" "973P73.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Vest, Patch Pockets and Police Badge Yellow Star Pattern" "973P74.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Vest, Slingshot in Belt Pattern" "973PAD.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Voldemort Robe Pattern" "973PH3.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Waistcoat, White Shirt and Bandolier Pattern" "973PQ3.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Waiter Pattern" "973P20.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"War Machine Armoured Suit Pattern" "973PBD.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"White/Blue Triangles, Blue/White Amulet Pattern" "973PWC.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"White/Blue Triangles, Red/White Amulet Pattern" "973PWB.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"White/Red Armour and White Belt" "973PWF.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"White Braces and Cartridge Belt Pattern" "973PW6.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"White Buttons and Police Badge Plain Sticker" "973D03.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"White Diagonal Zip and Pocket Pattern" "973p0a.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"White Envelope and Zipper Pattern" "973P7X.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"White Rope & Patched Collar Pattern" "973pdg.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"White Shirt and Jacket Pattern" "973P03.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"White Suit, Brown Vest and Tie Pattern" "973PA4.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Windsurfboard Pattern" "973P2D.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Wolfpack Pattern" "973P44.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Yellow Buttons and Grey Belt Sticker" "973D02.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Yellow Chest and White Beads Necklace Pattern" "973PD14.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Yellow Futuron Pattern" "973P6E.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Zipper and Police Badge Plain Pattern" "973P1G.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Zipper Jacket and 3 Pockets Pattern" "973P1U.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Zipper Jacket and Police Logo Pattern" "973P75.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"--------------------Non-standard torsi------------------------------------------" "" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Baby Body with Bodysuit" "15526.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Mechanical Head and Torso" "53988.DAT" 0 1 0 0 0 1 0 0 0 1 0 -8 0 +"Mechanical Torso" "30375.DAT" 0 1 0 0 0 1 0 0 0 1 0 40 0 +"Mechanical Torso with Blue Insignia" "30375PS3.DAT" 0 1 0 0 0 1 0 0 0 1 0 40 0 +"Mechanical Torso with Orange Insignia" "30375PS1.DAT" 0 1 0 0 0 1 0 0 0 1 0 40 0 +"Mechanical Torso with Tan Insignia" "30375PS2.DAT" 0 1 0 0 0 1 0 0 0 1 0 40 0 +"Mechanical Torso with 4 Side Attachment Cylinders" "54275.DAT" 0 1 0 0 0 1 0 0 0 1 0 10 0 +"Skeleton Torso" "6260.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Skeleton Torso with Shoulder Rods" "60115.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Torso with Integral Arms" "17.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"--------------------------------------------------------------------------------" "" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"None" "" 0 1 0 0 0 1 0 0 0 1 0 0 0 + + + +[BODY2] +"Plain" "3815.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 + +; Update 2015-01 +"Black Belt with Silver Belt Buckle Pattern" "3815P8I.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 + +"Clockwork Robot Pattern" "3815PC67.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Dark Grey Belt with Silver Buckle and Rivets Pattern" "3815PAW.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Gold Belt and DarkBlue Loincloth Pattern" "3815PQ0.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Gold Belt and Orange Cable Pattern" "3815P6U.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Gold O-Belt and Loincloth Pattern" "3815PQ2.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Gold X-Belt and Decorated Loincloth Pattern" "3815PQ1.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Harlequin Black Square Pattern" "3815PBA.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Holster and Belt Pattern" "3815PA9.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Iron Man Armoured Suit Mark XLII Pattern" "3815PBF.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Iron Man Armoured Suit Mark XVII Pattern" "3815PBE.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Iron Patriot Armoured Suit Pattern" "3815PBG.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Laboratory Smock Pattern" "3815PDE.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Leather Belt (Red Studs) Pattern" "3815p4f.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"LOTR Coat, Shirttails and Belt Pattern" "3815PM2.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"LOTR Dark Red Belt & Scale Armor Pattern" "3815PM1.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"LOTR Leather Armor" "3815PM0.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Purple Greatcoat Pattern" "3815phb.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Red/White Triangles Pattern" "3815PW1.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Robot Pattern" "3815p63.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Silver Belt Pattern" "3815P6W.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Silver Belt and Salmon Cable Pattern" "3815P6V.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Studded Belt Pattern" "3815PC44.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"SW Gunbelt Pattern" "3815ps5.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"SW Stormtrooper Pattern" "3815PSK.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"War Machine Armoured Suit Pattern" "3815PBD.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"White Apron Pattern" "3815P89.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 + +; Update 2015-01 +"White and Gold Markings Pattern" "3815P6G.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 + + +"--------------------Non-standard hips-------------------------------------------" "" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Hips and Legs Short with Hole" "41879B.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Hips and Legs Short without Hole" "41879A.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Hips and Legs Short with Horizontal Stripe" "16709.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Hips and Legs Short with Yellow Horizontal Stripe Pattern" "16709P01.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Hips and Legs Short w. Stripe, Slingshot on Back Pattern" "16709P02.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Legs Old" "15.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Martian Legs" "30530.DAT" 0 1 0 0 0 1 0 0 0 1 0 48 0 +"Mechanical Legs" "30376.DAT" 0 1 0 0 0 1 0 0 0 1 0 46 0 +"Slope Brick 65 2x2x2" "3678a.DAT" 0 -1 0 0 0 1 0 0 0 -1 0 0 0 +"Slope Brick 65 2x2x2 with DkGn Dress Pattern" "3678bp4x.DAT" 0 -1 0 0 0 1 0 0 0 -1 0 0 0 +"Slope Brick 65 2x2x2 with Queen's Dress Pattern" "3678ap4h.DAT" 0 -1 0 0 0 1 0 0 0 -1 0 0 0 +"Slope Brick 65 2x2x2 with White Apron Pattern" "3678bp4w.DAT" 0 -1 0 0 0 1 0 0 0 -1 0 0 0 +"Slope Brick 65 2x2x2 with Witch's Dress Pattern" "3678ap01.DAT" 0 -1 0 0 0 1 0 0 0 -1 0 0 0 +"--------------------------------------------------------------------------------" "" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"None" "" 0 1 0 0 0 1 0 0 0 1 0 0 0 + + + +[BODY3] +"None" "" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Armour SW Clone Trooper Tasset" "61190c.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Skirt 0.7L with 11 Diamond Points" "16820C01.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Skirt 1.1L with Straight Bottom" "600880C01.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Skirt 1.1L w. Straight Bottom w. Dark Green Apron Pattern" "600880P01C01.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Skirt 1.4L with Straight Bottom" "U9209C01.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Skirt 1.4L w. Straight Bottom w. White Apron Pattern" "U9209P01C01.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Skirt 1.5L Fringed" "14295C01.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Skirt 1.5L Fringed with Stepped Edge" "18200C01.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"--------------------------------------------------------------------------------" "" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"None" "" 0 1 0 0 0 1 0 0 0 1 0 0 0 + + + +[NECK] +"None" "" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"--------------------------------------------------------------------------------" "" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Armour Plate" "2587.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 + +; Update 2015-01 +"Armour Plate with LOTR King Theoden Pattern" "2587PM0.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 + +"Armour Samurai" "30174.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Armour Shoulder" "30121.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Armour Shoulder Pads w. 1 Stud on Front, 2 Studs on Back" "11097.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Armour SW Clone Trooper Pauldron" "61190b.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Armour SW Clone Trooper Tasset" "61190c.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Backpack Openable Closed" "30158c01.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Backpack Skydiver" "12897.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Bandana" "30133.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Bat Wing" "98722.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Beard Long Forked" "60750.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Beard Long with Five Braids" "60749.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Beard Short" "15501.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Beard with Rounded End" "10052.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Bracket 1 x 1 - 1 x 1" "42446.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Cape Cloth (Formed)" "50231C01.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Cape Cloth Floating (Formed)" "50231C02.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Cape Cloth Scalloped 5 Points (Formed)" "56630C01.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Cape Cloth Short (Formed)" "99464C01.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Cape Cloth with Holes and Tattered Edges (Formed)" "86038C01.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Cape Cloth with Inside Dark Red Pattern (Formed)" "50231P01C01.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Eagle Wing" "93250.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Minifig Eagle Wing with Tan Feathers and Red/Gold Pattern" "93250PQ0.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Epaulette" "2526.DAT" 0 1 0 0 0 1 0 0 0 1 0 -2 0 +"Airtanks" "3838.DAT" 0 1 0 0 0 1 0 0 0 1 0 -2 0 +"Arrow Quiver" "4498.DAT" 0 -1 0 0 0 1 0 0 0 -1 0 0 0 +"Backpack Non-Opening" "2524.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Cape" "4524.DAT" 0 1 0 0 0 1 0 0 0 1 0 -2 0 +"Container D-Basket" "4523.DAT" 0 1 0 0 0 1 0 0 0 1 0 1 0 +"Hair Beard" "6132.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Jet Pack with 2 Octagonal Nozzles" "6023.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Jet-Pack with Stud On Front" "4736.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Lifevest" "2610.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Sack" "92590.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Satchel (on right shoulder)" "61976.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Satchel (on left shoulder)" "61976.DAT" 0 -1 0 0 0 1 0 0 0 -1 0 0 0 +"Scabbard for Two Swords" "88290.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Scuba Tank" "30091.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Sword Scabbard (on right shoulder)" "95348.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Sword Scabbard (on left shoulder)" "95348.DAT" 0 -1 0 0 0 1 0 0 0 -1 0 0 0 +"Vest" "3840.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Vest with Crown on Dark Pink Sticker" "3840D01.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Vest with Crown on Violet Sticker" "3840D05.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Vest with Green Chevrons on Yellow Sticker" "3840D03.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Vest with Green Chevrons on Yellow.LtGrey Sticker" "3840D07.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Vest with White Maltese Cross on Red Sticker" "3840D02.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Vest with White Maltese Cross on Red/LtGrey Sticker" "3840D06.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Vest with Yellow Trefoils on Blue Sticker" "3840D04.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Vest with Yellow Trefoils on DkBlue Sticker" "3840D08.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 + + + +[LARM] +"Right" "3818.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Bionicle Arm Barraki" "57588.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Mechanical Arm" "30377.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Mechanical Arm Straight" "59230.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Mechanical Arm with Clip and Rod Hole" "53989.DAT" 0 0 0 1 0 1 0 -1 0 0 0 0 0 +"Mechanical Arm with Clip and Rod Hole" "76116.DAT" 0 0 0 1 0 1 0 -1 0 0 0 0 0 +"Short Sleeve and Yellow Arm Pattern" "3818P01.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Skeleton Arm" "6265.DAT" 0 1 0 0 0 1 0 0 0 1 -6 0 0.5 +"Wiry Bent with Clip" "10058.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 + +"--------------------------------------------------------------------------------" "" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"None" "" 0 1 0 0 0 1 0 0 0 1 0 0 0 + + + +[RARM] +"Left" "3819.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Bionicle Arm Barraki" "57588.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Mechanical Arm" "30377.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Mechanical Arm Straight" "59230.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Mechanical Arm with Clip and Rod Hole" "53989.DAT" 0 0 0 1 0 1 0 -1 0 0 0 0 0 +"Mechanical Arm with Clip and Rod Hole" "76116.DAT" 0 0 0 1 0 1 0 -1 0 0 0 0 0 +"Short Sleeve and Yellow Arm Pattern" "3819P01.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Skeleton Arm" "6265.DAT" 0 1 0 0 0 1 0 0 0 1 6 0 0.5 +"Wiry Bent with Clip" "10058.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 + +"--------------------------------------------------------------------------------" "" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"None" "" 0 1 0 0 0 1 0 0 0 1 0 0 0 + + + +[LHAND] +"Hand" "3820.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Hand Hook" "2531.DAT" 0 1 0 0 0 1 0 0 0 1 0 0.4 0 +"--------------------------------------------------------------------------------" "" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"None" "" 0 1 0 0 0 1 0 0 0 1 0 0 0 + + + +[RHAND] +"Hand" "3820.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Hand Hook" "2531.DAT" 0 -1 0 0 0 1 0 0 0 1 0 0.4 0 +"--------------------------------------------------------------------------------" "" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"None" "" 0 1 0 0 0 1 0 0 0 1 0 0 0 + + + +[LHANDA] +"None" "" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"--------------------------------------------------------------------------------" "" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Animal Snake" "30115.dat" 0 0.469472 0 -0.882948 0.882948 0 0.469472 0 -1 0 0 -4 -4 +"Animal Starfish" "33122.dat" 0 -1 0 0 0 0 1 0 1 0 0 -26 -6 +"Axe with Twin-Blade" "95052.DAT" 0 1 0 0 0 1 0 0 0 1 0 -1 0 +"Battleaxe" "3848.dat" 0 -1 0 0 0 1 0 0 0 -1 0 0 0 +"Bar 0.5L with Blade 3L" "64727.dat" 0 1 0 0 0 1 0 0 0 1 0 -8 0 +"Bar 0.5L with Curved Blade 2L" "87747.dat" 0 1 0 0 0 1 0 0 0 1 0 -8 0 +"Bar 0.5L with Faceted Spike 1L" "88695.dat" 0 1 0 0 0 1 0 0 0 1 0 -8 0 +"Bar 1.5L with Clip" "48729.dat" 0 1 0 0 0 1 0 0 0 1 0 -20 0 +"Bar 3L" "87994.dat" 0 1 0 0 0 1 0 0 0 1 0 -40 0 +"Bar 3L with White Ends Pattern" "87994p01.dat" 0 1 0 0 0 1 0 0 0 1 0 -40 0 +"Bar 4L Light Sabre Blade" "30374.dat" 0 1 0 0 0 -1 0 0 0 -1 0 12 0 +"Bar 4.5L Straight" "71184.dat" 0 1 0 0 0 1 0 0 0 1 0 20 0 +"Bar 4.5L with Handle" "87618.dat" 0 -1 0 0 0 -1 0 0 0 1 0 -80 0 +"Bar 6L with Thick Stop" "63965.dat" 0 1 0 0 0 1 0 0 0 1 0 -8 0 +"Bar 6.6L with Stop" "4095.dat" 0 1 0 0 0 1 0 0 0 1 0 -8 0 +"Barbed Wire Loop" "62700.dat" 0 0 -1 0 -1 0 0 0 0 -1 0 -2 0 +"Batarang" "55707c.dat" 0 0 1 0 -1 0 0 0 0 1 0 -2 0 +"Binoculars with Round Eyepiece" "30162.dat" 0 1 0 0 0 0 -1 0 1 0 -5 -1.6 0 +"Bone 2L" "93160.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Bone 5L" "92691.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Bottle Cylindrical" "95228.dat" 0 1 0 0 0 1 0 0 0 1 0 -12 0 +"Bottle Cylindrical with Bottle Ship Pattern" "95228p01.dat" 0 1 0 0 0 1 0 0 0 1 0 -12 0 +"Bow with Arrow" "4499.dat" 0 0 0 -1 0 1 0 1 0 0 0 1 0 + +; Update 2015-01 +"Brick 1 x 2 x 0.667 with 8 Studs and Angled Handle" "15071.DAT" 0 1 0 0 0 0.920505 0.390731 0 -0.390731 0.920505 0 -11 0 + +"Broom" "4332.dat" 0 -1 0 0 0 1 0 0 0 -1 0 -76 0 +"Bucket 1 x 1 x 1 Conical with Raised Handle" "95343C01.DAT" 0 0 -0.642788 -0.766044 1 0 0 0 -0.766044 0.642788 0 -1.5 0 +"Bucket 1 x 1 x 1 Cylindrical with Raised Handle" "12884C01.DAT" 0 0 -0.642788 -0.766044 1 0 0 0 -0.766044 0.642788 0 -1.5 0 +"Bugle" "71342.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Camera Movie" "30148.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Camera Snapshot" "30089.dat" 0 0 0.5 0.866025 0 0.866025 -0.5 -1 0 0 -4.062 2.5 -18 +"Camera with Side Sight" "4360.dat" 0 0 0 1 0 1 0 -1 0 0 0 -24 6.5 +"Castle Lance" "3849.dat" 0 1 0 0 0 0 1 0 -1 0 0 40 0 +"Chainsaw Blade" "6117.DAT" 0 1 0 0 0 0 -1 0 1 0 0 -11 -8 +"Cheerleader Pom Pom" "87997.DAT" 0 1 0 0 0 1 0 0 0 1 0 5 0 +"Cheerleader Pom Pom with Blue Pattern" "87997p01.DAT" 0 1 0 0 0 1 0 0 0 1 0 5 0 +"Cheerleader Pom Pom with Red Pattern" "87997p02.DAT" 0 1 0 0 0 1 0 0 0 1 0 5 0 +"Circular Blade Saw" "30194.dat" 0 -1 0 0 0 -0.422618 0.906308 0 0.906308 0.422618 0 15 -17 +"Coin with '1' Gothic Type" "96904.dat" 0 0 1 0 0 0 -1 -1 0 0 -2 -4 -10 +"Coin with '2' Gothic Type" "96905.dat" 0 0 1 0 0 0 -1 -1 0 0 -2 -4 -10 +"Coin with '5' Gothic Type" "96906.dat" 0 0 1 0 0 0 -1 -1 0 0 -2 -4 -10 +"Coin with '10' Gothic Type" "96907.dat" 0 0 1 0 0 0 -1 -1 0 0 -2 -4 -10 +"Coin with '10' Sans-serif Type" "70501a.dat" 0 0 1 0 0 0 -1 -1 0 0 -2 -4 -10 +"Coin with '20' Sans-serif Type" "70501b.dat" 0 0 1 0 0 0 -1 -1 0 0 -2 -4 -10 +"Coin with '30' Sans-serif Type" "70501c.dat" 0 0 1 0 0 0 -1 -1 0 0 -2 -4 -10 +"Coin with '40' Sans-serif Type" "70501d.dat" 0 0 1 0 0 0 -1 -1 0 0 -2 -4 -10 +"Comb" "30112b.dat" 0 1 0 0 0 1 0 0 0 1 0 -1 0 +"Compass" "889c01.dat" 0 1 0 0 0 1 0 0 0 1 0 -3 0 +"Conical Flask" "u9180.dat" 0 1 0 0 0 1 0 0 0 1 0 -10 0 +"Conical Flask TransClear with Coloured Base" "u9180c01.dat" 0 1 0 0 0 1 0 0 0 1 0 -10 0 +"Crossbow" "2570.dat" 0 1 0 0 0 1 0 0 0 1 0 -3 0 +"Cup" "3899.dat" 0 1 0 0 0 1 0 0 0 1 0 -15 -20 +"Dagger" "88288.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Dagger with Pearl Light Gray Blade" "88288P01.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Dinner Plate" "6256.dat" 0 0.0954045 -0.866025 -0.490814 0.981627 0 0.190809 -0.165245 -0.5 0.850114 7 -5 -26 +"Dynamite Sticks Bundle" "64728.dat" 0 0.5 0 0.866025 0 1 0 -0.866025 0 0.5 0 -28 -9 +"Electric Guitar" "93564.dat" 0 0 0 1 0 1 0 -1 0 0 0 4 0 +"Electric Guitar, Silver Strings, White Body" "93564P01.dat" 0 0 0 1 0 1 0 -1 0 0 0 4 0 +"Electric Guitar, Black Strings, DkPink Lightning" "93564P02.dat" 0 0 0 1 0 1 0 -1 0 0 0 4 0 +"Figure Club" "60659.dat" 0 1 0 0 0 1 0 0 0 1 0 3 0 +"Food Apple" "33051.dat" 0 0.857167 0.515038 0 -0.515038 0.857167 0 0 0 1 14 33 0 +"Food Banana" "33085.dat" 0 0 -1 0 1 0 0 0 0 1 0 0 0 +"Food Carrot" "33172.dat" 0 1 0 0 0 1 0 0 0 1 0 -50 0 +"Food Carrot Top" "33183.dat" 0 1 0 0 0 1 0 0 0 1 0 12 0 +"Food Carrot with Bright_Green Leaves" "33172c02.dat" 0 1 0 0 0 1 0 0 0 1 0 10 0 +"Food Carrot with Green Leaves" "33172c01.dat" 0 1 0 0 0 1 0 0 0 1 0 10 0 +"Food Cherry" "22667.dat" 0 1 0 0 0 1 0 0 0 1 0 -11 0 +"Food Croissant" "33125.dat" 0 0 1 0 -0.819152 0 0.573576 0.573576 0 0.819152 4 -27 -9 +"Food French Bread" "4342.dat" 0 0 -0.292372 0.956305 1 0 0 0 0.956305 0.292372 4.5 0 5 +"Food Ice Cream Cone" "33120.dat" 0 1 0 0 0 1 0 0 0 1 0 -2 0 +"Food Popsicle" "30222.dat" 0 1 0 0 0 1 0 0 0 1 0 -3 0 +"Food Sausage" "33078.dat" 0 0 -1 0 1 0 0 0 0 1 0 0 0 +"Food Turkey Leg" "33057.dat" 0 0 0.985 -0.174 0 0.174 0.985 1 0 0 9 -24 -1 +"Friends Access. Bag Round with Ruffle" "93090.DAT" 0 0 0 -1 1 0 0 0 -1 0 0 -1 -28 +"Friends Access. Bag Round w. Bright Pink Ruffle Pattern" "93090P01.DAT" 0 0 0 1 -1 0 0 0 -1 0 0 -1 -28 +"Friends Access. Bag Round w. Dark Pink Ruffle Pattern" "93090P02.DAT" 0 0 0 1 -1 0 0 0 -1 0 0 -1 -28 +"Friends Access. Bag Round w. Light Aqua Ruffle Pattern" "93090P03.DAT" 0 0 0 1 -1 0 0 0 -1 0 0 -1 -28 +"Friends Access. Basket" "93092.DAT" 0 1 0 0 0 0 1 0 -1 0 -15 -2 -29 +"Friends Access. Comb with Handle and 3 Hearts" "96482.DAT" 0 1 0 0 0 1 0 0 0 1 0 9 0 +"Friends Access. Cupcake Case" "97784.DAT" 0 1 0 0 0 1 0 0 0 1 0 -3 0 +"Friends Access. Cutlery Fork" "97781.DAT" 0 0 0 -1 0 1 0 1 0 0 0 -1 0 +"Friends Access. Cutlery Knife" "97782.DAT" 0 1 0 0 0 1 0 0 0 1 0 -1 0 +"Friends Access. Dish Rectangular" "97785.DAT" 0 1 0 0 0 1 0 0 0 1 0 -12 0 +"Friends Access. Dish Round 2.7 x 2.7" "97783.DAT" 0 1 0 0 0 1 0 0 0 1 0 -12 0 +"Friends Access. Frying Pan" "97790.DAT" 0 0 0 1 -1 0 0 0 -1 0 0 -56 -12 +"Friends Access. Hair Brush with Heart on Reverse" "96480.DAT" 0 0 0 -1 0 1 0 1 0 0 0 9 0 +"Friends Access. Hair Dryer" "96484.DAT" 0 1 0 0 0 1 0 0 0 1 0 8 0 +"Friends Access. Hand-held Food Mixer" "97793.DAT" 0 1 0 0 0 0 1 0 -1 0 0 -3 0 +"Friends Access. Lipstick with Light Bluish Grey Handle" "93094.DAT" 0 1 0 0 0 1 0 0 0 1 0 6 0 +"Friends Access. Mixing Bowl" "97791.DAT" 0 1 0 0 0 1 0 0 0 1 0 -12 0 +"Friends Access. Spatula with 3 Holes" "97787.DAT" 0 1 0 0 0 1 0 0 0 1 0 -1 0 +"Frypan" "4528.dat" 0 0 1 0 0 0 1 1 0 0 -4 -24 0 +"Goblet" "2343.dat" 0 1 0 0 0 1 0 0 0 1 0 -26 0 +"Goblet with Hollow Stem" "6269.dat" 0 1 0 0 0 1 0 0 0 1 0 -26 0 +"Gun Flintlock Pistol" "2562.dat" 0 1 0 0 0 1 0 0 0 1 0 -1 0 +"Gun Laser Kryptonian" "13952.DAT" 0 1 0 0 0 1 0 0 0 1 0 2 0 +"Gun Laser Pistol" "87993.dat" 0 1 0 0 0 1 0 0 0 1 0 -4 0 +"Gun Long Blaster" "57899.dat" 0 1 0 0 0 1 0 0 0 1 0 -20 0 +"Gun Musket" "2561.dat" 0 0 0.707 0.707 0 0.707 -0.707 -1 0 0 -25.1 -33.7 0 +"Gun Revolver" "30132.dat" 0 1 0 0 0 1 0 0 0 1 0 -3 0 +"Gun Rifle" "30141.dat" 0 0 0 1 0 1 0 -1 0 0 0 -8 0 +"Gun Semiautomatic Pistol" "55707a.dat" 0 1 0 0 0 1 0 0 0 1 0 -20 0 +"Gun Shooting Blaster with Dark Bluish Grey Trigger" "15391c01.DAT" 0 1 0 0 0 1 0 0 0 1 0 4 0 +"Gun Shooting Blaster with Trigger and TrOrange Projectile" "15391C02.DAT" 0 1 0 0 0 1 0 0 0 1 0 4 0 +"Gun SW Short Blaster" "58247.dat" 0 1 0 0 0 1 0 0 0 1 0 -3 0 +"Gun SW Small Blaster DC-17" "61190a.dat" 0 1 0 0 0 1 0 0 0 1 0 -3 0 +"Hairbrush" "3852.dat" 0 -1 0 0 0 1 0 0 0 -1 2.7 -8 0 +"Hand Fan" "93553.dat" 0 1 0 0 0 1 0 0 0 1 0 2 0 +"Hand Truck (Shortcut)" "2495c01.dat" 0 1 0 0 0 0 1 0 -1 0 22 -4 -58 +"Handcuffs" "61482.dat" 0 1 0 0 0 1 0 0 0 1 24 16 12 +"Harpoon" "57467.dat" 0 1 0 0 0 1 0 0 0 1 0 28 0 +"Hose Nozzle with Side String Hole" "58367.dat" 0 1 0 0 0 1 0 0 0 1 0 -2 0 +"Hose Nozzle with Side String Hole Simplified" "60849.dat" 0 1 0 0 0 1 0 0 0 1 0 -2 0 +"Ice Axe" "30193.dat" 0 1 0 0 0 1 0 0 0 1 0 6 0 +"Jackhammer" "30228.dat" 0 0.326 0 0.946 -0.899 -0.309 0.31 0.292 -0.951 0.101 2.5 -18.5 11 +"Key" "62808.DAT" 0 1 0 0 0 1 0 0 0 1 0 -2 0 +"Knife" "37.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Knife with Flat Hilt End" "95054.DAT" 0 1 0 0 0 1 0 0 0 1 0 -3 0 +"Ladle" "4337.dat" 0 1 0 0 0 1 0 0 0 1 0 -36 0 +"Life Ring" "30340.dat" 0 0 1 0 0 0 1 1 0 0 -4 16 -21 +"Lightning" "59233.dat" 0 1 0 0 0 1 0 0 0 1 0 -2 0 +"Lightsaber Chrome Silver - 1 Side On" "577Bc01.dat" 0 1 0 0 0 1 0 0 0 1 0 -20 0 +"Lightsaber Chrome Silver - 2 Sides On" "577Bc02.dat" 0 1 0 0 0 1 0 0 0 1 0 -20 0 +"Lightsaber Hilt with Bottom Ring" "577B.dat" 0 1 0 0 0 1 0 0 0 1 0 -20 0 +"Long Bow with Arrow" "93231.dat" 0 0.966 0 -0.259 0 1 0 0.259 0 0.966 0 -11 0 +"Loudhailer" "4349.dat" 0 1 0 0 0 1 0 0 0 1 0 -16 0 +"Loudhailer with Orange Stripe Pattern" "4349P01.DAT" 0 1 0 0 0 1 0 0 0 1 0 -16 0 +"Machine Gun with Drum Magazine" "55707b.dat" 0 1 0 0 0 1 0 0 0 1 0 -16 0 +"Magic Wand" "6124.dat" 0 1 0 0 0 1 0 0 0 1 0 8 0 +"Maracas" "90508.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Maracas with Green Border" "90508P01.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Medical Thermometer" "98393D.DAT" 0 0 0 1 0 1 0 -1 0 0 0 -26 -5 +"Metal Detector" "4479.dat" 0 1 0 0 0 1 0 0 0 1 0 -24 0 +"Microphone" "90370.dat" 0 1 0 0 0 1 0 0 0 1 0 -8 0 +"Microphone with Metallic Silver Top" "90370p01.dat" 0 1 0 0 0 1 0 0 0 1 0 -8 0 +"Mug" "33054.dat" 0 1 0 0 0 1 0 0 0 1 0 -12 -20 +"Pharaoh's Staff with Forked End" "93252.dat" 0 1 0 0 0 1 0 0 0 1 0 -42 0 +"Paint Brush" "93552.dat" 0 1 0 0 0 1 0 0 0 1 0 16 0 +"Paint Brush w. Silver Ring, Green Tip" "93552P01.dat" 0 1 0 0 0 1 0 0 0 1 0 16 0 +"Paint Palette" "93551.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Paint Palette with Paint Drops Pattern" "93551P01.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Paint Roller Brush Handle" "12885.DAT" 0 1 0 0 0 1 0 0 0 1 0 8 0 +"Pike / Spear Elaborate with Metallic Silver Head" "90391P01.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Pike / Spear Elaborate with Flat Silver Head" "90391P02.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Pipe Wrench" "4328.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Pitchfork" "4496.dat" 0 1 0 0 0 1 0 0 0 1 0 -12 0 +"Plant Flower Stem w. Bar w. 3 Flowers" "99249C01.DAT" 0 1 0 0 0 1 0 0 0 1 0 6 0 +"Plant Flower Stem w. Bar w. 3 Flowers w. 6 Rounded Petals" "99249C03.DAT" 0 1 0 0 0 1 0 0 0 1 0 6 0 +"Plant Flower Stem w. Bar w. 3 Roses" "99249C02.DAT" 0 1 0 0 0 1 0 0 0 1 0 6 0 +"Plunger" "11459.DAT" 0 1 0 0 0 -1 0 0 0 -1 0 -20 0 +"Plunger with Medium Dark Flesh Handle" "11459P01.DAT" 0 1 0 0 0 -1 0 0 0 -1 0 -20 0 +"Polearm Halberd" "6123.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Pushbroom" "3836.dat" 0 0 0 -1 0 -1 0 -1 0 0 0 44 0 +"Radio with Long Handle" "3962b.dat" 0 0 0 -1 0 1 0 1 0 0 0 -1 0 +"Radio with Short Handle" "3962a.dat" 0 0 0 -1 0 1 0 1 0 0 0 -1 0 +"Ring 1 x 1" "11010.dat" 0 0 -1 0 -1 0 0 0 0 -1 -4 -2 -6 +"Ring with Triangle" "87748.dat" 0 0 1 0 -0.866 0 0.5 0.5 0 0.866 0 -2 -25 +"Ring with Triangle with Gold Bands and Crab Pattern" "87748P01.dat" 0 0 1 0 -0.866 0 0.5 0.5 0 0.866 0 -2 -25 +"Ring with Triangle with Gold Bands and Manta Ray Pattern" "87748P05.dat" 0 0 1 0 -0.866 0 0.5 0.5 0 0.866 0 -2 -25 +"Ring with Triangle with Gold Bands and Shark Pattern" "87748P03.dat" 0 0 1 0 -0.866 0 0.5 0.5 0 0.866 0 -2 -25 +"Ring with Triangle with Gold Bands and Squid Pattern" "87748P04.dat" 0 0 1 0 -0.866 0 0.5 0.5 0 0.866 0 -2 -25 +"Ring with Triangle with Gold Bands and Triangle Pattern" "87748P06.dat" 0 0 1 0 -0.866 0 0.5 0.5 0 0.866 0 -2 -25 +"Ring with Triangle with Gold Bands and Turtle Pattern" "87748p02.dat" 0 0 1 0 -0.866 0 0.5 0.5 0 0.866 0 -2 -25 +"Rock 1 x 1 Gem Facetted" "30153.dat" 0 1 0 0 0 1 0 0 0 1 0 -8 0 +"Saucepan" "4529.dat" 0 0 1 0 0 0 1 1 0 0 -6 -24 0 +"Saxophone" "13808.DAT" 0 1 0 0 0 1 0 0 0 1 0 7 0 +"Saxophone with Black Mouthpiece" "13808P01.DAT" 0 1 0 0 0 1 0 0 0 1 0 7 0 +"Sextant" "30154.dat" 0 0 0 1 0 1 0 -1 0 0 0 -35 0 +"Shield Broad with Spiked Bottom and Cutout Corner" "10049.dat" 0 0 0 1 -1 0 0 0 -1 0 -4 -1 0 +"Shield Broad w. Spiked Bottom, Cutout Corner, Hand Pattern" "10049P01.dat" 0 0 0 1 -1 0 0 0 -1 0 -4 -1 0 +"Shield Octagonal with Stud" "48494.dat" 0 0 0 1 -1 0 0 0 -1 0 0 -2 0 +"Shield Octagonal without Stud" "61856.dat" 0 0 0 1 -1 0 0 0 -1 0 0 -2 0 +"Shield Octagonal with Troll Skull on Dark Red Pattern" "61856P40.dat" 0 0 0 1 -1 0 0 0 -1 0 0 -2 0 +"Shield Oval" "92747.dat" 0 0 0 1 -1 0 0 0 -1 0 -4 -1 0 +"Shield Oval with SW Gungan Patrol Shield" "92747p01.dat" 0 0 0 1 -1 0 0 0 -1 0 -4 -1 0 +"Shield Ovoid" "2586.dat" 0 0 0 1 -1 0 0 0 -1 0 -4 -1 0 +"Shield Ovoid with American Indian Pattern" "2586PW1.dat" 0 0 0 1 -1 0 0 0 -1 0 -4 -1 0 +"Shield Ovoid with Bat Pattern" "2586P4F.dat" 0 0 0 1 -1 0 0 0 -1 0 -4 -1 0 +"Shield Ovoid with Blue Dragon Pattern" "2586P4C.dat" 0 0 0 1 -1 0 0 0 -1 0 -4 -1 0 +"Shield Ovoid with Bull Head Pattern" "2586P4G.DAT" 0 0 0 1 -1 0 0 0 -1 0 -4 -1 0 + +; Update 2015-01 +"Shield Ovoid with Bull Head on Brown Border Sticker" "2586D01.DAT" 0 0 0 1 -1 0 0 0 -1 0 -4 -1 0 + +"Shield Ovoid with Crown on Dark/Med Blue Quarters Pattern" "2586P4J.DAT" 0 0 0 1 -1 0 0 0 -1 0 -4 -1 0 +"Shield Ovoid with DkGreen Dragon on MdDkFlesh/Tan Pattern" "2586P4K.DAT" 0 0 0 1 -1 0 0 0 -1 0 -4 -1 0 +"Shield Ovoid with Golden Lion Pattern" "2586PH1.DAT" 0 0 0 1 -1 0 0 0 -1 0 -4 -1 0 +"Shield Ovoid with Gold Lion on Red/White Quarters Pattern" "2586P4L.DAT" 0 0 0 1 -1 0 0 0 -1 0 -4 -1 0 +"Shield Ovoid with Green Dragon Pattern" "2586P4B.dat" 0 0 0 1 -1 0 0 0 -1 0 -4 -1 0 +"Shield Ovoid with Indigo Islanders Pattern" "2586P30.dat" 0 0 0 1 -1 0 0 0 -1 0 -4 -1 0 +"Shield Ovoid with Royal Knights Lion Pattern" "2586P4D.dat" 0 0 0 1 -1 0 0 0 -1 0 -4 -1 0 +"Shield Ovoid with Silver Skull on Dark Red Pattern" "2586P4H.DAT" 0 0 0 1 -1 0 0 0 -1 0 -4 -1 0 +"Shield Ovoid with Silver Snake Pattern" "2586PH2.DAT" 0 0 0 1 -1 0 0 0 -1 0 -4 -1 0 +"Shield Ovoid with SW Gungan Patrol Pattern" "2586PS1.DAT" 0 0 0 1 -1 0 0 0 -1 0 -4 -1 0 +"Shield Rectangular Curved with Stud" "98367.DAT" 0 0 0 -1 1 0 0 0 -1 0 0 -1 0 +"Shield Round" "3876.dat" 0 0 0 1 0 1 0 -1 0 0 0 -12 0 +"Shield Round Bowed" "75902.dat" 0 0 0 1 -1 0 0 0 -1 0 -4 -1 0 +"Shield Round Bowed with Bullseye with Star Pattern" "75902P02.dat" 0 0 0 1 -1 0 0 0 -1 0 -4 -1 0 +"Shield Round Bowed with DkGreen and Gold Rohan" "75902P01.dat" 0 0 0 1 -1 0 0 0 -1 0 -4 -1 0 +"Shield Round Bowed with Gold Eagle Pattern" "75902P03.DAT" 0 0 0 1 -1 0 0 0 -1 0 -4 -1 0 +"Shield Round Bowed with Mercedes-Benz Logo" "75902P04.DAT" 0 0 0 1 -1 0 0 0 -1 0 -4 -1 0 +"Shield Round Flat" "59231.dat" 0 0 0 1 0 1 0 -1 0 0 -10 -12 0 +"Shield Round Flat with Silver Skull on Dark Red Pattern" "59231P4H.dat" 0 0 0 1 0 1 0 -1 0 0 -10 -12 0 +"Shield Round Type 2" "91884.DAT" 0 0 0 1 1 0 0 0 1 0 -4 -2 0 +"Shield Round Type 2 w. Aztec Bird on Dark Red Pattern" "91884P04.DAT" 0 0 0 1 1 0 0 0 1 0 -4 -2 0 +"Shield Round Type 2 w. DkBrown Ring and 4 Rivets Pattern" "91884P01.DAT" 0 0 0 1 1 0 0 0 1 0 -4 -2 0 +"Shield Round Type 2 w. Dragon Heads and Ornaments Pattern" "91884P03.DAT" 0 0 0 1 1 0 0 0 1 0 -4 -2 0 +"Shield Round Type 2 w. Silver Rivets Pattern" "91884P02.DAT" 0 0 0 1 1 0 0 0 1 0 -4 -2 0 +"Shield Scarab" "93251.dat" 0 0 0 1 -1 0 0 0 -1 0 -9 -1 -1 +"Shield Triangular" "3846.dat" 0 0 0 1 0 1 0 -1 0 0 0 -12 0 +"Shield Triangular with Bat Pattern" "3846p4f.dat" 0 0 0 1 0 1 0 -1 0 0 0 -12 0 +"Shield Triangular with Black Falcon Blue Border Pattern" "3846p45.dat" 0 0 0 1 0 1 0 -1 0 0 0 -12 0 +"Shield Triangular with Black Falcon Yellow Border Pattern" "3846p46.dat" 0 0 0 1 0 1 0 -1 0 0 0 -12 0 +"Shield Triangular with Blue Dragon Pattern" "3846p4c.dat" 0 0 0 1 0 1 0 -1 0 0 0 -12 0 +"Shield Triangular with Blue Lion on Yellow Background" "3846p4g.dat" 0 0 0 1 0 1 0 -1 0 0 0 -12 0 +"Shield Triangular with Crown on Dark/Med Blue Quarters" "3846P4J.dat" 0 0 0 1 0 1 0 -1 0 0 0 -12 0 +"Shield Triangular with Crown on Dark-Pink Sticker" "3846d01.dat" 0 0 0 1 0 1 0 -1 0 0 0 -12 0 +"Shield Triangular with Crown on Violet Sticker" "3846d05.dat" 0 0 0 1 0 1 0 -1 0 0 0 -12 0 +"Shield Triangular with Dragon on MdDkFlesh/Tan Pattern" "3846P4K.dat" 0 0 0 1 0 1 0 -1 0 0 0 -12 0 +"Shield Triangular with Forestman Pattern" "3846p48.dat" 0 0 0 1 0 1 0 -1 0 0 0 -12 0 +"Shield Triangular w. Gold Lion on Red/White Quart. Patt." "3846P4L.dat" 0 0 0 1 0 1 0 -1 0 0 0 -12 0 +"Shield Triangular with Green Chevrons on Yellow Sticker" "3846d03.dat" 0 0 0 1 0 1 0 -1 0 0 0 -12 0 +"Shield Triangular with Green Chevrons on Yellow.LtGray" "3846d06.dat" 0 0 0 1 0 1 0 -1 0 0 0 -12 0 +"Shield Triangular with Lion Head, Blue & Yellow Pattern" "3846p4e.dat" 0 0 0 1 0 1 0 -1 0 0 0 -12 0 +"Shield Triangular with Maroon/Red Quarters Pattern" "3846p4u.dat" 0 0 0 1 0 1 0 -1 0 0 0 -12 0 +"Shield Triangular with Red and Gray Pattern, Blue Frame" "3846p47.dat" 0 0 0 1 0 1 0 -1 0 0 0 -12 0 +"Shield Triangular with Red Cross and Helmet" "3846p01.dat" 0 0 0 1 0 1 0 -1 0 0 0 -12 0 +"Shield Triangular with Red/Peach Quarters Pattern" "3846p4t.dat" 0 0 0 1 0 1 0 -1 0 0 0 -12 0 +"Shield Triangular with Royal Knights Lion Pattern" "3846p4d.dat" 0 0 0 1 0 1 0 -1 0 0 0 -12 0 +"Shield Triangular with White Maltese Cross on Red Sticker" "3846d02.dat" 0 0 0 1 0 1 0 -1 0 0 0 -12 0 +"Shield Triangular with Wolfpack Pattern" "3846p44.dat" 0 0 0 1 0 1 0 -1 0 0 0 -12 0 +"Shield Triangular with Yellow Lion on Blue Background" "3846p4h.dat" 0 0 0 1 0 1 0 -1 0 0 0 -12 0 +"Shield Triangular with Yellow Trefoils on Blue Sticker" "3846d04.dat" 0 0 0 1 0 1 0 -1 0 0 0 -12 0 +"Shield Triangular with Yellow Trefoils on DkBlue Sticker" "3846d07.dat" 0 0 0 1 0 1 0 -1 0 0 0 -12 0 +"Shovel" "3837.dat" 0 1 0 0 0 1 0 0 0 1 0 -12 0 +"Signal Holder" "3900.dat" 0 1 0 0 0 0 -1 0 1 0 0 -36 -2 +"Signal Holder with Black 'POLICE' and Red Line Pattern" "3900P01.DAT" 0 1 0 0 0 0 -1 0 1 0 0 -36 -2 +"Signal Holder with Green Circle on White Sticker" "3900d01.dat" 0 1 0 0 0 0 -1 0 1 0 0 -36 -2 +"Ski Pole" "90540.dat" 0 1 0 0 0 1 0 0 0 1 0 -8 0 +"Sledgehammer" "75904.dat" 0 0 0 1 0 1 0 -1 0 0 0 -14 0 +"Small Bow with Arrow" "95051.DAT" 0 0 0 1 0 1 0 -1 0 0 0 -10 0 +"Space Scanner Tool" "30035.dat" 0 1 0 0 0 1 0 0 0 1 0 -19 -10 +"Spear" "4497.dat" 0 1 0 0 0 1 0 0 0 1 0 -40 0 +"Spear with Four Side Blades" "43899.dat" 0 1 0 0 0 1 0 0 0 1 0 -144 0 +"Speargun" "30088.dat" 0 1 0 0 0 1 0 0 0 1 0 -13 0 +"Staff with Crescent End" "95050.DAT" 0 1 0 0 0 1 0 0 0 1 0 -1 0 +"Staff with Spherical End" "95049.DAT" 0 1 0 0 0 1 0 0 0 1 0 -1 0 +"Statuette" "90398.dat" 0 1 0 0 0 1 0 0 0 1 0 -1 0 +"Steak on Bone" "98372.dat" 0 1 0 0 0 1 0 0 0 1 0 -2 0 +"Steak on Bone with Red Meat" "98372P01.dat" 0 1 0 0 0 1 0 0 0 1 0 -2 0 +"Stretcher with Bottom Hinges" "4714.DAT" 0 0 0 -1 1 0 0 0 -1 0 26 -74 -2 +"Stretcher without Bottom Hinges" "93140.DAT" 0 0 0 -1 1 0 0 0 -1 0 26 -74 -2 +"Suitcase" "4449.dat" 0 0 0 -1 1 0 0 0 -1 0 0 0 0 +"Sword Cutlass" "2530.dat" 0 1 0 0 0 1 0 0 0 1 0 -2 0 +"Sword Greatsword" "59.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Sword Katana Type 1 (Octogonal Guard)" "30173a.dat" 0 1 0 0 0 1 0 0 0 1 0 6 0 +"Sword Katana Type 2 (Square Guard)" "30173b.dat" 0 1 0 0 0 1 0 0 0 1 0 6 0 +"Sword Khopesh" "93247.dat" 0 1 0 0 0 1 0 0 0 1 0 -8 0 +"Sword Longsword" "98370.dat" 0 1 0 0 0 1 0 0 0 1 0 -8 0 +"Sword Rapier" "93550.dat" 0 1 0 0 0 1 0 0 0 1 0 -2 0 +"Sword Roman Gladius" "95673.dat" 0 1 0 0 0 1 0 0 0 1 0 -8 0 +"Sword Saber with Clip Pommel" "59229.dat" 0 1 0 0 0 1 0 0 0 1 0 -2 0 +"Sword Scimitar" "43887.dat" 0 1 0 0 0 1 0 0 0 1 0 -18 0 +"Sword Scimitar with Jagged Edge" "60752.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Sword Shortsword" "3847.dat" 0 1 0 0 0 1 0 0 0 1 0 -12 0 +"Sword Small with Angular Guard" "95053.DAT" 0 1 0 0 0 1 0 0 0 1 0 -3 0 +"Sword Small with Curved Blade" "10053.DAT" 0 1 0 0 0 1 0 0 0 1 0 -2 0 +"Sword Uruk-Hai" "10050.dat" 0 -1 0 0 0 1 0 0 0 -1 0 4 0 +"Sword Sword with Angular Hilt" "48495.dat" 0 0 0 -1 0 1 0 1 0 0 0 -10 0 +"Syringe" "87989.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Telescope" "64644.dat" 0 1 0 0 0 1 0 0 0 1 0 -11 0 +"Tennis Racket" "93216.dat" 0 1 0 0 0 1 0 0 0 1 0 -3 0 +"Tomahawk with Flat-Silver Blade" "13571.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Tool 4-Way Lug Wrench" "604553.DAT" 0 1 0 0 0 1 0 0 0 1 0 -12 0 +"Tool Adjustable Wrench with 3-Rib Handle" "604614.DAT" 0 1 0 0 0 1 0 0 0 1 0 -2 0 +"Tool Battery Powered Drill" "604549.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Tool Binoculars Space" "30304.dat" 0 1 0 0 0 0 -1 0 1 0 -5 -1 0 +"Tool Box Wrench" "55300.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Tool Box Wrench with 3-Rib Handle" "604552.DAT" 0 1 0 0 0 1 0 0 0 1 0 -2 0 + +; Update 2015-01 +"Tool Crowbar" "92585.DAT" 0 1 0 0 0 1 0 0 0 1 0 -30 0 + +"Tool Fishing Rod" "2614.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Tool Grappling Hook" "30192.dat" 0 1 0 0 0 -1 0 0 0 -1 0 9 0 +"Tool Hammer" "55295.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Tool Hammer with 3-Rib Handle" "604547.DAT" 0 1 0 0 0 1 0 0 0 1 0 -2 0 +"Tool Handaxe" "3835.dat" 0 1 0 0 0 1 0 0 0 1 0 -16 0 +"Tool Hose Nozzle with Handle" "4210a.dat" 0 -1 0 0 0 1 0 0 0 -1 0 -12 0 +"Tool Magnifying Glass" "30152.dat" 0 1 0 0 0 1 0 0 0 1 0 -52 0 +"Tool Mallet" "4522.dat" 0 0 0 1 0 1 0 -1 0 0 0 -28 0 +"Tool Oar" "2542.dat" 0 -1 0 0 0 -1 0 0 0 1 0 40 0 +"Tool Oilcan" "55296.DAT" 0 1 0 0 0 1 0 0 0 1 0 -6 0 +"Tool Oilcan with Ribbed Handle" "604548.DAT" 0 1 0 0 0 1 0 0 0 1 0 -3 0 +"Tool Open End Wrench" "55299.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Tool Open End Wrench with 3-Rib Handle" "604551.DAT" 0 1 0 0 0 1 0 0 0 1 0 -2 0 +"Tool Pickaxe" "3841.dat" 0 1 0 0 0 1 0 0 0 1 0 -12 0 +"Tool Power Drill" "55297.dat" 0 1 0 0 0 1 0 0 0 1 0 -6 0 +"Tool Screwdriver" "55298.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Tool Screwdriver with Wide Head and 3-Rib Handle" "604550.DAT" 0 1 0 0 0 1 0 0 0 1 0 -2 0 +"Tool Socket Wrench with Ratchet and 3-Rib Handle" "604615.DAT" 0 1 0 0 0 1 0 0 0 1 0 -2 0 +"Tool Spanner/Screwdriver" "4006.dat" 0 0 0 -1 0 1 0 1 0 0 0 -14 0 +"Toolbox 1 x 3 with Handle" "98368.dat" 0 0 0 1 -1 0 0 0 -1 0 0 -2 0 +"Torch" "3959.dat" 0 1 0 0 0 1 0 0 0 1 0 -13 0 +"Torch without Grooves" "86208.dat" 0 1 0 0 0 1 0 0 0 1 0 -13 0 +"Toy Winder Key" "98375.dat" 0 0 0 -1 1 0 0 0 -1 0 0 -2 -20 +"Tray Oval" "11252.dat" 0 0 -1 0 1 0 0 0 0 1 -6 -3 -16 +"Underwater Scooter" "30092.dat" 0 -1 0 0 0 1 0 0 0 -1 20 -22 -8.5 +"Weapon Billy Club" "13790.DAT" 0 1 0 0 0 1 0 0 0 1 0 -7.5 0 +"Weapon Bladed Claw" "88811.dat" 0 1 0 0 0 1 0 0 0 1 0 2 0 +"Weapon Club with Spikes" "88001.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Weapon Crescent Blade Serrated with Bar 0.5L" "98141.dat" 0 1 0 0 0 1 0 0 0 1 0 2 0 +"Weapon Curved Blade 8.5L with Bar 1.5L" "98137.dat" 0 1 0 0 0 1 0 0 0 1 0 12 0 +"Weapon Hand Dagger" "88812.dat" 0 1 0 0 0 1 0 0 0 1 0 2 0 +"Weapon Trident" "92290.dat" 0 1 0 0 0 1 0 0 0 1 0 24 0 +"Welding Gas Torch with Hose and Gas Cylinder Top" "13793.DAT" 0 1 0 0 0 1 0 0 0 1 30 35 0 +"Whip" "2488.dat" 0 1 0 0 0 1 0 0 0 1 0 -8 0 +"Whip in Latched Position (Shortcut)" "2488c01.dat" 0 1 0 0 0 1 0 0 0 1 0 -8 0 +"Whip Coiled" "61975.dat" 0 0 0 -1 0 1 0 1 0 0 0 -8 0 +"Wine Glass" "33061.dat" 0 1 0 0 0 1 0 0 0 1 0 -32 0 +"Zip Line Handle" "30229.dat" 0 1 0 0 0 1 0 0 0 1 0 -12 0 + + + +[RHANDA] +"None" "" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"--------------------------------------------------------------------------------" "" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Animal Snake" "30115.dat" 0 -0.469472 0 0.882948 0.882948 0 0.469472 0 1 0 0 -4 4 +"Animal Starfish" "33122.dat" 0 -1 0 0 0 0 1 0 1 0 0 -26 -6 +"Axe with Twin-Blade" "95052.DAT" 0 1 0 0 0 1 0 0 0 1 0 -1 0 +"Battleaxe" "3848.dat" 0 -1 0 0 0 1 0 0 0 -1 0 0 0 +"Bar 0.5L with Blade 3L" "64727.dat" 0 1 0 0 0 1 0 0 0 1 0 -8 0 +"Bar 0.5L with Curved Blade 2L" "87747.dat" 0 1 0 0 0 1 0 0 0 1 0 -8 0 +"Bar 0.5L with Faceted Spike 1L" "88695.dat" 0 1 0 0 0 1 0 0 0 1 0 -8 0 +"Bar 1.5L with Clip" "48729.dat" 0 1 0 0 0 1 0 0 0 1 0 -20 0 +"Bar 3L" "87994.dat" 0 1 0 0 0 1 0 0 0 1 0 -40 0 +"Bar 3L with White Ends Pattern" "87994p01.dat" 0 1 0 0 0 1 0 0 0 1 0 -40 0 +"Bar 4L Light Sabre Blade" "30374.dat" 0 1 0 0 0 -1 0 0 0 -1 0 12 0 +"Bar 4.5L Straight" "71184.dat" 0 1 0 0 0 1 0 0 0 1 0 20 0 +"Bar 4.5L with Handle" "87618.dat" 0 -1 0 0 0 -1 0 0 0 1 0 -80 0 +"Bar 6L with Thick Stop" "63965.dat" 0 1 0 0 0 1 0 0 0 1 0 -8 0 +"Bar 6.6L with Stop" "4095.dat" 0 1 0 0 0 1 0 0 0 1 0 -8 0 +"Barbed Wire Loop" "62700.dat" 0 0 -1 0 -1 0 0 0 0 -1 0 -2 0 +"Batarang" "55707c.dat" 0 0 1 0 -1 0 0 0 0 1 0 -2 0 +"Binoculars with Round Eyepiece" "30162.dat" 0 1 0 0 0 0 -1 0 1 0 -5 -1.6 0 +"Bone 2L" "93160.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Bone 5L" "92691.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Bottle Cylindrical" "95228.dat" 0 1 0 0 0 1 0 0 0 1 0 -12 0 +"Bottle Cylindrical with Bottle Ship Pattern" "95228p01.dat" 0 1 0 0 0 1 0 0 0 1 0 -12 0 +"Bow with Arrow" "4499.dat" 0 0 0 -1 0 1 0 1 0 0 0 1 0 + +; Update 2015-01 +"Brick 1 x 2 x 0.667 with 8 Studs and Angled Handle" "15071.DAT" 0 1 0 0 0 0.920505 0.390731 0 -0.390731 0.920505 0 -11 0 + +"Broom" "4332.dat" 0 -1 0 0 0 1 0 0 0 -1 0 -76 0 +"Bucket 1 x 1 x 1 Conical with Raised Handle" "95343C01.DAT" 0 0 0.642788 -0.766044 1 0 0 0 -0.766044 -0.642788 0 -1.5 0 +"Bucket 1 x 1 x 1 Cylindrical with Raised Handle" "12884C01.DAT" 0 0 0.642788 -0.766044 1 0 0 0 -0.766044 -0.642788 0 -1.5 0 +"Bugle" "71342.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Camera Movie" "30148.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Camera Snapshot" "30089.dat" 0 0 0.5 0.866025 0 0.866025 -0.5 -1 0 0 -4.062 2.5 -18 +"Camera with Side Sight" "4360.dat" 0 0 0 1 0 1 0 -1 0 0 0 -24 6.5 +"Castle Lance" "3849.dat" 0 1 0 0 0 0 1 0 -1 0 0 40 0 +"Chainsaw Blade" "6117.DAT" 0 1 0 0 0 0 -1 0 1 0 0 -11 -8 +"Cheerleader Pom Pom" "87997.DAT" 0 1 0 0 0 1 0 0 0 1 0 5 0 +"Cheerleader Pom Pom with Blue Pattern" "87997p01.DAT" 0 1 0 0 0 1 0 0 0 1 0 5 0 +"Cheerleader Pom Pom with Red Pattern" "87997p02.DAT" 0 1 0 0 0 1 0 0 0 1 0 5 0 +"Circular Blade Saw" "30194.dat" 0 -1 0 0 0 -0.422618 0.906308 0 0.906308 0.422618 0 15 -17 +"Coin with '1' Gothic Type" "96904.dat" 0 0 1 0 0 0 -1 -1 0 0 -2 -4 -10 +"Coin with '2' Gothic Type" "96905.dat" 0 0 1 0 0 0 -1 -1 0 0 -2 -4 -10 +"Coin with '5' Gothic Type" "96906.dat" 0 0 1 0 0 0 -1 -1 0 0 -2 -4 -10 +"Coin with '10' Gothic Type" "96907.dat" 0 0 1 0 0 0 -1 -1 0 0 -2 -4 -10 +"Coin with '10' Sans-serif Type" "70501a.dat" 0 0 1 0 0 0 -1 -1 0 0 -2 -4 -10 +"Coin with '20' Sans-serif Type" "70501b.dat" 0 0 1 0 0 0 -1 -1 0 0 -2 -4 -10 +"Coin with '30' Sans-serif Type" "70501c.dat" 0 0 1 0 0 0 -1 -1 0 0 -2 -4 -10 +"Coin with '40' Sans-serif Type" "70501d.dat" 0 0 1 0 0 0 -1 -1 0 0 -2 -4 -10 +"Conical Flask" "u9180.dat" 0 1 0 0 0 1 0 0 0 1 0 -10 0 +"Conical Flask TransClear with Coloured Base" "u9180c01.dat" 0 1 0 0 0 1 0 0 0 1 0 -10 0 +"Comb" "30112b.dat" 0 1 0 0 0 1 0 0 0 1 0 -1 0 +"Compass" "889c01.dat" 0 1 0 0 0 1 0 0 0 1 0 -3 0 +"Crossbow" "2570.dat" 0 1 0 0 0 1 0 0 0 1 0 -3 0 +"Cup" "3899.dat" 0 1 0 0 0 1 0 0 0 1 0 -15 -20 +"Dagger" "88288.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Dagger with Pearl Light Gray Blade" "88288P01.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Dinner Plate" "6256.dat" 0 -0.0954045 0.866025 0.490814 -0.981627 0 -0.190809 -0.165245 -0.5 0.850114 -7 -5 -26 +"Dynamite Sticks Bundle" "64728.dat" 0 0.5 0 0.866025 0 1 0 -0.866025 0 0.5 0 -28 -9 +"Electric Guitar" "93564.dat" 0 0 0 -1 0 1 0 1 0 0 0 4 0 +"Electric Guitar, Silver Strings, White Body" "93564P01.dat" 0 0 0 -1 0 1 0 1 0 0 0 4 0 +"Electric Guitar, Black Strings, DkPink Lightning" "93564P02.dat" 0 0 0 -1 0 1 0 1 0 0 0 4 0 +"Figure Club" "60659.dat" 0 1 0 0 0 1 0 0 0 1 0 3 0 +"Food Apple" "33051.dat" 0 0.857167 0.515038 0 -0.515038 0.857167 0 0 0 1 14 33 0 +"Food Banana" "33085.dat" 0 0 -1 0 1 0 0 0 0 1 0 0 0 +"Food Carrot" "33172.dat" 0 1 0 0 0 1 0 0 0 1 0 -50 0 +"Food Carrot Top" "33183.dat" 0 1 0 0 0 1 0 0 0 1 0 12 0 +"Food Carrot with Bright_Green Leaves" "33172c02.dat" 0 1 0 0 0 1 0 0 0 1 0 10 0 +"Food Carrot with Green Leaves" "33172c01.dat" 0 1 0 0 0 1 0 0 0 1 0 10 0 +"Food Cherry" "22667.dat" 0 1 0 0 0 1 0 0 0 1 0 -11 0 +"Food Croissant" "33125.dat" 0 0 1 0 -0.819152 0 0.573576 0.573576 0 0.819152 4 -27 -9 +"Food French Bread" "4342.dat" 0 0 0.292372 0.956305 1 0 0 0 0.956305 -0.292372 -4.5 0 5 +"Food Ice Cream Cone" "33120.dat" 0 1 0 0 0 1 0 0 0 1 0 -2 0 +"Food Popsicle" "30222.dat" 0 1 0 0 0 1 0 0 0 1 0 -3 0 +"Food Sausage" "33078.dat" 0 0 -1 0 1 0 0 0 0 1 0 0 0 +"Food Turkey Leg" "33057.dat" 0 0 -0.985 0.174 0 0.174 0.985 -1 0 0 -9 -24 -1 +"Friends Access. Bag Round with Ruffle" "93090.DAT" 0 0 0 -1 1 0 0 0 -1 0 0 -1 -28 +"Friends Access. Bag Round w. Bright Pink Ruffle Pattern" "93090P01.DAT" 0 0 0 -1 1 0 0 0 -1 0 0 -1 -28 +"Friends Access. Bag Round w. Dark Pink Ruffle Pattern" "93090P02.DAT" 0 0 0 -1 1 0 0 0 -1 0 0 -1 -28 +"Friends Access. Bag Round w. Light Aqua Ruffle Pattern" "93090P03.DAT" 0 0 0 -1 1 0 0 0 -1 0 0 -1 -28 +"Friends Access. Basket" "93092.DAT" 0 1 0 0 0 0 1 0 -1 0 15 -2 -29 +"Friends Access. Comb with Handle and 3 Hearts" "96482.DAT" 0 1 0 0 0 1 0 0 0 1 0 9 0 +"Friends Access. Cupcake Case" "97784.DAT" 0 1 0 0 0 1 0 0 0 1 0 -3 0 +"Friends Access. Cutlery Fork" "97781.DAT" 0 0 0 1 0 1 0 -1 0 0 0 -1 0 +"Friends Access. Cutlery Knife" "97782.DAT" 0 1 0 0 0 1 0 0 0 1 0 -1 0 +"Friends Access. Dish Rectangular" "97785.DAT" 0 1 0 0 0 1 0 0 0 1 0 -12 0 +"Friends Access. Dish Round 2.7 x 2.7" "97783.DAT" 0 1 0 0 0 1 0 0 0 1 0 -12 0 +"Friends Access. Frying Pan" "97790.DAT" 0 0 0 1 -1 0 0 0 -1 0 0 -56 -12 +"Friends Access. Hair Brush with Heart on Reverse" "96480.DAT" 0 0 0 1 0 1 0 -1 0 0 0 9 0 +"Friends Access. Hair Dryer" "96484.DAT" 0 1 0 0 0 1 0 0 0 1 0 8 0 +"Friends Access. Hand-held Food Mixer" "97793.DAT" 0 1 0 0 0 0 1 0 -1 0 0 -3 0 +"Friends Access. Lipstick with Light Bluish Grey Handle" "93094.DAT" 0 1 0 0 0 1 0 0 0 1 0 6 0 +"Friends Access. Mixing Bowl" "97791.DAT" 0 1 0 0 0 1 0 0 0 1 0 -12 0 +"Friends Access. Spatula with 3 Holes" "97787.DAT" 0 1 0 0 0 1 0 0 0 1 0 -1 0 +"Frypan" "4528.dat" 0 0 1 0 0 0 1 1 0 0 -4 -24 0 +"Goblet" "2343.dat" 0 1 0 0 0 1 0 0 0 1 0 -26 0 +"Goblet with Hollow Stem" "6269.dat" 0 1 0 0 0 1 0 0 0 1 0 -26 0 +"Gun Flintlock Pistol" "2562.dat" 0 1 0 0 0 1 0 0 0 1 0 -1 0 +"Gun Laser Kryptonian" "13952.DAT" 0 1 0 0 0 1 0 0 0 1 0 2 0 +"Gun Laser Pistol" "87993.dat" 0 1 0 0 0 1 0 0 0 1 0 -4 0 +"Gun Long Blaster" "57899.dat" 0 1 0 0 0 1 0 0 0 1 0 -20 0 +"Gun Musket" "2561.dat" 0 0 0.707 0.707 0 0.707 -0.707 -1 0 0 -25.1 -33.7 0 +"Gun Revolver" "30132.dat" 0 1 0 0 0 1 0 0 0 1 0 -3 0 +"Gun Rifle" "30141.dat" 0 0 0 1 0 1 0 -1 0 0 0 -8 0 +"Gun Semiautomatic Pistol" "55707a.dat" 0 1 0 0 0 1 0 0 0 1 0 -20 0 +"Gun Shooting Blaster with Dark Bluish Grey Trigger" "15391c01.DAT" 0 1 0 0 0 1 0 0 0 1 0 4 0 +"Gun Shooting Blaster with Trigger and TrOrange Projectile" "15391C02.DAT" 0 1 0 0 0 1 0 0 0 1 0 4 0 +"Gun SW Short Blaster" "58247.dat" 0 1 0 0 0 1 0 0 0 1 0 -3 0 +"Gun SW Small Blaster DC-17" "61190a.dat" 0 1 0 0 0 1 0 0 0 1 0 -3 0 +"Hairbrush" "3852.dat" 0 -1 0 0 0 1 0 0 0 -1 2.7 -8 0 +"Hand Fan" "93553.dat" 0 1 0 0 0 1 0 0 0 1 0 2 0 +"Hand Truck (Shortcut)" "2495c01.dat" 0 1 0 0 0 0 1 0 -1 0 -22 -4 -58 +"Handcuffs" "61482.dat" 0 1 0 0 0 1 0 0 0 1 -24 16 12 +"Harpoon" "57467.dat" 0 1 0 0 0 1 0 0 0 1 0 28 0 +"Hose Nozzle with Side String Hole" "58367.dat" 0 1 0 0 0 1 0 0 0 1 0 -2 0 +"Hose Nozzle with Side String Hole Simplified" "60849.dat" 0 1 0 0 0 1 0 0 0 1 0 -2 0 +"Ice Axe" "30193.dat" 0 1 0 0 0 1 0 0 0 1 0 6 0 +"Jackhammer" "30228.dat" 0 0.326 0 -0.946 0.899 -0.309 0.31 -0.292 -0.951 -0.101 -2.5 -18.5 11 +"Key" "62808.DAT" 0 1 0 0 0 1 0 0 0 1 0 -2 0 +"Knife" "37.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Knife with Flat Hilt End" "95054.DAT" 0 1 0 0 0 1 0 0 0 1 0 -3 0 +"Ladle" "4337.dat" 0 1 0 0 0 1 0 0 0 1 0 -36 0 +"Life Ring" "30340.dat" 0 0 -1 0 0 0 1 -1 0 0 4 16 -21 +"Lightning" "59233.dat" 0 1 0 0 0 1 0 0 0 1 0 -2 0 +"Lightsaber Chrome Silver - 1 Side On" "577Bc01.dat" 0 1 0 0 0 1 0 0 0 1 0 -20 0 +"Lightsaber Chrome Silver - 2 Sides On" "577Bc02.dat" 0 1 0 0 0 1 0 0 0 1 0 -20 0 +"Lightsaber Hilt with Bottom Ring" "577B.dat" 0 1 0 0 0 1 0 0 0 1 0 -20 0 +"Long Bow with Arrow" "93231.dat" 0 0.966 0 0.259 0 1 0 -0.259 0 0.966 0 -11 0 +"Loudhailer" "4349.dat" 0 1 0 0 0 1 0 0 0 1 0 -16 0 +"Loudhailer with Orange Stripe Pattern" "4349P01.DAT" 0 1 0 0 0 1 0 0 0 1 0 -16 0 +"Machine Gun with Drum Magazine" "55707b.dat" 0 1 0 0 0 1 0 0 0 1 0 -16 0 +"Magic Wand" "6124.dat" 0 1 0 0 0 1 0 0 0 1 0 8 0 +"Maracas" "90508.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Maracas with Green Border" "90508P01.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Medical Thermometer" "98393D.DAT" 0 0 0 1 0 1 0 -1 0 0 0 -26 -5 +"Metal Detector" "4479.dat" 0 1 0 0 0 1 0 0 0 1 0 -24 0 +"Microphone" "90370.dat" 0 1 0 0 0 1 0 0 0 1 0 -8 0 +"Microphone with Metallic Silver Top" "90370p01.dat" 0 1 0 0 0 1 0 0 0 1 0 -8 0 +"Mug" "33054.dat" 0 1 0 0 0 1 0 0 0 1 0 -12 -20 +"Pharaoh's Staff with Forked End" "93252.dat" 0 1 0 0 0 1 0 0 0 1 0 -42 0 +"Paint Brush" "93552.dat" 0 1 0 0 0 1 0 0 0 1 0 16 0 +"Paint Brush w. Silver Ring, Green Tip" "93552P01.dat" 0 1 0 0 0 1 0 0 0 1 0 16 0 +"Paint Palette" "93551.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Paint Palette with Paint Drops Pattern" "93551P01.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Paint Roller Brush Handle" "12885.dat" 0 1 0 0 0 1 0 0 0 1 0 8 0 +"Pike / Spear Elaborate with Metallic Silver Head" "90391P01.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Pike / Spear Elaborate with Flat Silver Head" "90391P02.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Pipe Wrench" "4328.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Pitchfork" "4496.dat" 0 1 0 0 0 1 0 0 0 1 0 -12 0 +"Plant Flower Stem w. Bar w. 3 Flowers" "99249C01.DAT" 0 1 0 0 0 1 0 0 0 1 0 6 0 +"Plant Flower Stem w. Bar w. 3 Flowers w. 6 Rounded Petals" "99249C03.DAT" 0 1 0 0 0 1 0 0 0 1 0 6 0 +"Plant Flower Stem w. Bar w. 3 Roses" "99249C02.DAT" 0 1 0 0 0 1 0 0 0 1 0 6 0 +"Plunger" "11459.DAT" 0 1 0 0 0 -1 0 0 0 -1 0 -20 0 +"Plunger with Medium Dark Flesh Handle" "11459P01.DAT" 0 1 0 0 0 -1 0 0 0 -1 0 -20 0 +"Polearm Halberd" "6123.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Pushbroom" "3836.dat" 0 0 0 -1 0 -1 0 -1 0 0 0 44 0 +"Radio with Long Handle" "3962b.dat" 0 0 0 -1 0 1 0 1 0 0 0 -1 0 +"Radio with Short Handle" "3962a.dat" 0 0 0 -1 0 1 0 1 0 0 0 -1 0 +"Ring 1 x 1" "11010.dat" 0 0 -1 0 -1 0 0 0 0 -1 -4 -2 -6 +"Ring with Triangle" "87748.dat" 0 0 -1 0 0.866025 0 -0.5 0.5 0 0.866026 0 -2 -25 +"Ring with Triangle with Gold Bands and Crab Pattern" "87748P01.dat" 0 0 -1 0 0.866025 0 -0.5 0.5 0 0.866026 0 -2 -25 +"Ring with Triangle with Gold Bands and Manta Ray Pattern" "87748P05.dat" 0 0 -1 0 0.866025 0 -0.5 0.5 0 0.866026 0 -2 -25 +"Ring with Triangle with Gold Bands and Shark Pattern" "87748P03.dat" 0 0 -1 0 0.866025 0 -0.5 0.5 0 0.866026 0 -2 -25 +"Ring with Triangle with Gold Bands and Squid Pattern" "87748P04.dat" 0 0 -1 0 0.866025 0 -0.5 0.5 0 0.866026 0 -2 -25 +"Ring with Triangle with Gold Bands and Triangle Pattern" "87748P06.dat" 0 0 -1 0 0.866025 0 -0.5 0.5 0 0.866026 0 -2 -25 +"Ring with Triangle with Gold Bands and Turtle Pattern" "87748p02.dat" 0 0 -1 0 0.866025 0 -0.5 0.5 0 0.866026 0 -2 -25 +"Rock 1 x 1 Gem Facetted" "30153.dat" 0 1 0 0 0 1 0 0 0 1 0 -8 0 +"Saucepan" "4529.dat" 0 0 1 0 0 0 1 1 0 0 -6 -24 0 +"Saxophone" "13808.DAT" 0 1 0 0 0 1 0 0 0 1 0 7 0 +"Saxophone with Black Mouthpiece" "13808P01.DAT" 0 1 0 0 0 1 0 0 0 1 0 7 0 +"Sextant" "30154.dat" 0 0 0 1 0 1 0 -1 0 0 0 -35 0 +"Shield Broad with Spiked Bottom and Cutout Corner" "10049.dat" 0 0 0 -1 1 0 0 0 -1 0 4 -1 0 +"Shield Broad w. Spiked Bottom, Cutout Corner, Hand Pattern" "10049P01.dat" 0 0 0 -1 1 0 0 0 -1 0 4 -1 0 +"Shield Octagonal with Stud" "48494.dat" 0 0 0 -1 1 0 0 0 -1 0 0 -2 0 +"Shield Octagonal without Stud" "61856.dat" 0 0 0 -1 1 0 0 0 -1 0 0 -2 0 +"Shield Octagonal with Troll Skull on Dark Red Pattern" "61856P40.dat" 0 0 0 -1 1 0 0 0 -1 0 0 -2 0 +"Shield Oval" "92747.dat" 0 0 0 -1 1 0 0 0 -1 0 4 -1 0 +"Shield Oval with SW Gungan Patrol Shield" "92747p01.dat" 0 0 0 -1 1 0 0 0 -1 0 4 -1 0 +"Shield Ovoid" "2586.dat" 0 0 0 -1 1 0 0 0 -1 0 4 -1 0 +"Shield Ovoid with American Indian Pattern" "2586pw1.dat" 0 0 0 -1 1 0 0 0 -1 0 4 -1 0 +"Shield Ovoid with Bat Pattern" "2586P4F.dat" 0 0 0 -1 1 0 0 0 -1 0 4 -1 0 +"Shield Ovoid with Blue Dragon Pattern" "2586p4c.dat" 0 0 0 -1 1 0 0 0 -1 0 4 -1 0 +"Shield Ovoid with Bull Head Pattern" "2586P4G.DAT" 0 0 0 -1 1 0 0 0 -1 0 4 -1 0 + +; Update 2015-01 +"Shield Ovoid with Bull Head on Brown Border Sticker" "2586D01.DAT" 0 0 0 -1 1 0 0 0 -1 0 4 -1 0 + +"Shield Ovoid with Crown on Dark/Med Blue Quarters Pattern" "2586P4J.DAT" 0 0 0 -1 1 0 0 0 -1 0 4 -1 0 +"Shield Ovoid with DkGreen Dragon on MdDkFlesh/Tan Pattern" "2586P4K.DAT" 0 0 0 -1 1 0 0 0 -1 0 4 -1 0 +"Shield Ovoid with Golden Lion Pattern" "2586ph1.DAT" 0 0 0 -1 1 0 0 0 -1 0 4 -1 0 +"Shield Ovoid with Gold Lion on Red/White Quarters Pattern" "2586P4L.DAT" 0 0 0 -1 1 0 0 0 -1 0 4 -1 0 +"Shield Ovoid with Green Dragon Pattern" "2586p4b.dat" 0 0 0 -1 1 0 0 0 -1 0 4 -1 0 +"Shield Ovoid with Indigo Islanders Pattern" "2586P30.dat" 0 0 0 -1 1 0 0 0 -1 0 4 -1 0 +"Shield Ovoid with Royal Knights Lion Pattern" "2586p4d.dat" 0 0 0 -1 1 0 0 0 -1 0 4 -1 0 +"Shield Ovoid with Silver Skull on Dark Red Pattern" "2586P4H.DAT" 0 0 0 -1 1 0 0 0 -1 0 4 -1 0 +"Shield Ovoid with Silver Snake Pattern" "2586PH2.DAT" 0 0 0 -1 1 0 0 0 -1 0 4 -1 0 +"Shield Ovoid with SW Gungans Patrol Pattern" "2586ps1.DAT" 0 0 0 -1 1 0 0 0 -1 0 4 -1 0 +"Shield Rectangular Curved with Stud" "98367.DAT" 0 0 0 -1 1 0 0 0 -1 0 0 -1 0 +"Shield Round" "3876.dat" 0 0 0 -1 0 1 0 1 0 0 0 -12 0 +"Shield Round Bowed" "75902.dat" 0 0 0 -1 1 0 0 0 -1 0 4 -1 0 +"Shield Round Bowed with Bullseye with Star Pattern" "75902P02.dat" 0 0 0 -1 1 0 0 0 -1 0 4 -1 0 +"Shield Round Bowed with DkGreen and Gold Rohan" "75902P01.dat" 0 0 0 -1 1 0 0 0 -1 0 4 -1 0 +"Shield Round Bowed with Gold Eagle Pattern" "75902P03.DAT" 0 0 0 -1 1 0 0 0 -1 0 4 -1 0 +"Shield Round Bowed with Mercedes-Benz Logo" "75902P04.DAT" 0 0 0 -1 1 0 0 0 -1 0 4 -1 0 +"Shield Round Flat" "59231.dat" 0 0 0 -1 0 1 0 1 0 0 10 -12 0 +"Shield Round Flat with Silver Skull on Dark Red Pattern" "59231P4H.dat" 0 0 0 -1 0 1 0 1 0 0 10 -12 0 +"Shield Round Type 2" "91884.DAT" 0 0 0 -1 1 0 0 0 -1 0 4 -2 0 +"Shield Round Type 2 w. Aztec Bird on Dark Red Pattern" "91884P04.DAT" 0 0 0 -1 1 0 0 0 -1 0 4 -2 0 +"Shield Round Type 2 w. DkBrown Ring and 4 Rivets Pattern" "91884P01.DAT" 0 0 0 -1 1 0 0 0 -1 0 4 -2 0 +"Shield Round Type 2 w. Dragon Heads and Ornaments Pattern" "91884P03.DAT" 0 0 0 -1 1 0 0 0 -1 0 4 -2 0 +"Shield Round Type 2 w. Silver Rivets Pattern" "91884P02.DAT" 0 0 0 -1 1 0 0 0 -1 0 4 -2 0 +"Shield Scarab" "93251.dat" 0 0 0 -1 1 0 0 0 -1 0 9 -1 -1 +"Shield Triangular" "3846.dat" 0 0 0 -1 0 1 0 1 0 0 0 -12 0 +"Shield Triangular with Bat Pattern" "3846p4f.dat" 0 0 0 -1 0 1 0 1 0 0 0 -12 0 +"Shield Triangular with Black Falcon Blue Border Pattern" "3846p45.dat" 0 0 0 -1 0 1 0 1 0 0 0 -12 0 +"Shield Triangular with Black Falcon Yellow Border Pattern" "3846p46.dat" 0 0 0 -1 0 1 0 1 0 0 0 -12 0 +"Shield Triangular with Blue Dragon Pattern" "3846p4c.dat" 0 0 0 -1 0 1 0 1 0 0 0 -12 0 +"Shield Triangular with Blue Lion on Yellow Background" "3846p4g.dat" 0 0 0 -1 0 1 0 1 0 0 0 -12 0 +"Shield Triangular with Crown on Dark/Med Blue Quarters" "3846P4J.dat" 0 0 0 -1 0 1 0 1 0 0 0 -12 0 +"Shield Triangular with Crown on Dark-Pink Sticker" "3846d01.dat" 0 0 0 -1 0 1 0 1 0 0 0 -12 0 +"Shield Triangular with Crown on Violet Sticker" "3846d05.dat" 0 0 0 -1 0 1 0 1 0 0 0 -12 0 +"Shield Triangular with Dragon on MdDkFlesh/Tan Pattern" "3846P4K.dat" 0 0 0 -1 0 1 0 1 0 0 0 -12 0 +"Shield Triangular with Forestman Pattern" "3846p48.dat" 0 0 0 -1 0 1 0 1 0 0 0 -12 0 +"Shield Triangular w. Gold Lion on Red/White Quart. Patt." "3846P4L.dat" 0 0 0 -1 0 1 0 1 0 0 0 -12 0 +"Shield Triangular with Green Chevrons on Yellow Sticker" "3846d03.dat" 0 0 0 -1 0 1 0 1 0 0 0 -12 0 +"Shield Triangular with Green Chevrons on Yellow.LtGray" "3846d06.dat" 0 0 0 -1 0 1 0 1 0 0 0 -12 0 +"Shield Triangular with Lion Head, Blue & Yellow Pattern" "3846p4e.dat" 0 0 0 -1 0 1 0 1 0 0 0 -12 0 +"Shield Triangular with Maroon/Red Quarters Pattern" "3846p4u.dat" 0 0 0 -1 0 1 0 1 0 0 0 -12 0 +"Shield Triangular with Red and Gray Pattern, Blue Frame" "3846p47.dat" 0 0 0 -1 0 1 0 1 0 0 0 -12 0 +"Shield Triangular with Red Cross and Helmet" "3846p01.dat" 0 0 0 -1 0 1 0 1 0 0 0 -12 0 +"Shield Triangular with Red/Peach Quarters Pattern" "3846p4t.dat" 0 0 0 -1 0 1 0 1 0 0 0 -12 0 +"Shield Triangular with Royal Knights Lion Pattern" "3846p4d.dat" 0 0 0 -1 0 1 0 1 0 0 0 -12 0 +"Shield Triangular with White Maltese Cross on Red Sticker" "3846d02.dat" 0 0 0 -1 0 1 0 1 0 0 0 -12 0 +"Shield Triangular with Wolfpack Pattern" "3846p44.dat" 0 0 0 -1 0 1 0 1 0 0 0 -12 0 +"Shield Triangular with Yellow Lion on Blue Background" "3846p4h.dat" 0 0 0 -1 0 1 0 1 0 0 0 -12 0 +"Shield Triangular with Yellow Trefoils on Blue Sticker" "3846d04.dat" 0 0 0 -1 0 1 0 1 0 0 0 -12 0 +"Shield Triangular with Yellow Trefoils on DkBlue Sticker" "3846d07.dat" 0 0 0 -1 0 1 0 1 0 0 0 -12 0 +"Shovel" "3837.dat" 0 1 0 0 0 1 0 0 0 1 0 -12 0 +"Signal Holder" "3900.dat" 0 1 0 0 0 0 -1 0 1 0 0 -36 -2 +"Signal Holder with Black 'POLICE' and Red Line Pattern" "3900P01.DAT" 0 1 0 0 0 0 -1 0 1 0 0 -36 -2 +"Signal Holder with Green Circle on White Sticker" "3900d01.dat" 0 1 0 0 0 0 -1 0 1 0 0 -36 -2 +"Ski Pole" "90540.dat" 0 1 0 0 0 1 0 0 0 1 0 -8 0 +"Sledgehammer" "75904.dat" 0 0 0 1 0 1 0 -1 0 0 0 -14 0 +"Small Bow with Arrow" "95051.DAT" 0 0 0 1 0 1 0 -1 0 0 0 -10 0 +"Space Scanner Tool" "30035.dat" 0 1 0 0 0 1 0 0 0 1 0 -19 -10 +"Spear" "4497.dat" 0 1 0 0 0 1 0 0 0 1 0 -40 0 +"Spear with Four Side Blades" "43899.dat" 0 1 0 0 0 1 0 0 0 1 0 -144 0 +"Speargun" "30088.dat" 0 1 0 0 0 1 0 0 0 1 0 -13 0 +"Staff with Crescent End" "95050.DAT" 0 1 0 0 0 1 0 0 0 1 0 -1 0 +"Staff with Spherical End" "95049.DAT" 0 1 0 0 0 1 0 0 0 1 0 -1 0 +"Steak on Bone" "98372.dat" 0 1 0 0 0 1 0 0 0 1 0 -2 0 +"Steak on Bone with Red Meat" "98372P01.dat" 0 1 0 0 0 1 0 0 0 1 0 -2 0 +"Statuette" "90398.dat" 0 1 0 0 0 1 0 0 0 1 0 -1 0 +"Stretcher with Bottom Hinges" "4714.DAT" 0 0 0 -1 1 0 0 0 -1 0 -26 -74 -2 +"Stretcher without Bottom Hinges" "93140.DAT" 0 0 0 -1 1 0 0 0 -1 0 -26 -74 -2 +"Suitcase" "4449.dat" 0 0 0 -1 1 0 0 0 -1 0 0 0 0 +"Sword Cutlass" "2530.dat" 0 1 0 0 0 1 0 0 0 1 0 -2 0 +"Sword Greatsword" "59.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Sword Katana Type 1 (Octogonal Guard)" "30173a.dat" 0 1 0 0 0 1 0 0 0 1 0 6 0 +"Sword Katana Type 2 (Square Guard)" "30173b.dat" 0 1 0 0 0 1 0 0 0 1 0 6 0 +"Sword Khopesh" "93247.dat" 0 1 0 0 0 1 0 0 0 1 0 -8 0 +"Sword Longsword" "98370.dat" 0 1 0 0 0 1 0 0 0 1 0 -8 0 +"Sword Rapier" "93550.dat" 0 1 0 0 0 1 0 0 0 1 0 -2 0 +"Sword Roman Gladius" "95673.dat" 0 1 0 0 0 1 0 0 0 1 0 -8 0 +"Sword Saber with Clip Pommel" "59229.dat" 0 1 0 0 0 1 0 0 0 1 0 -2 0 +"Sword Scimitar" "43887.dat" 0 1 0 0 0 1 0 0 0 1 0 -18 0 +"Sword Scimitar with Jagged Edge" "60752.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Sword Shortsword" "3847.dat" 0 1 0 0 0 1 0 0 0 1 0 -12 0 +"Sword Small with Angular Guard" "95053.DAT" 0 1 0 0 0 1 0 0 0 1 0 -3 0 +"Sword Small with Curved Blade" "10053.DAT" 0 1 0 0 0 1 0 0 0 1 0 -2 0 +"Sword Uruk-Hai" "10050.dat" 0 -1 0 0 0 1 0 0 0 -1 0 4 0 +"Sword Sword with Angular Hilt" "48495.dat" 0 0 0 -1 0 1 0 1 0 0 0 -10 0 +"Syringe" "87989.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Telescope" "64644.dat" 0 1 0 0 0 1 0 0 0 1 0 -11 0 +"Tennis Racket" "93216.dat" 0 1 0 0 0 1 0 0 0 1 0 -3 0 +"Tomahawk with Flat-Silver Blade" "13571.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Tool 4-Way Lug Wrench" "604553.DAT" 0 1 0 0 0 1 0 0 0 1 0 -12 0 +"Tool Adjustable Wrench with 3-Rib Handle" "604614.DAT" 0 1 0 0 0 1 0 0 0 1 0 -2 0 +"Tool Battery Powered Drill" "604549.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Tool Binoculars Space" "30304.dat" 0 1 0 0 0 0 -1 0 1 0 -5 -1 0 +"Tool Box Wrench" "55300.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Tool Box Wrench with 3-Rib Handle" "604552.DAT" 0 1 0 0 0 1 0 0 0 1 0 -2 0 + +; Update 2015-01 +"Tool Crowbar" "92585.DAT" 0 1 0 0 0 1 0 0 0 1 0 -30 0 + +"Tool Fishing Rod" "2614.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Tool Grappling Hook" "30192.dat" 0 1 0 0 0 -1 0 0 0 -1 0 9 0 +"Tool Hammer" "55295.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Tool Hammer with 3-Rib Handle" "604547.DAT" 0 1 0 0 0 1 0 0 0 1 0 -2 0 +"Tool Handaxe" "3835.dat" 0 1 0 0 0 1 0 0 0 1 0 -16 0 +"Tool Hose Nozzle with Handle" "4210a.dat" 0 -1 0 0 0 1 0 0 0 -1 0 -12 0 +"Tool Magnifying Glass" "30152.dat" 0 1 0 0 0 1 0 0 0 1 0 -52 0 +"Tool Mallet" "4522.dat" 0 0 0 1 0 1 0 -1 0 0 0 -28 0 +"Tool Oar" "2542.dat" 0 -1 0 0 0 -1 0 0 0 1 0 40 0 +"Tool Oilcan" "55296.DAT" 0 1 0 0 0 1 0 0 0 1 0 -6 0 +"Tool Oilcan with Ribbed Handle" "604548.DAT" 0 1 0 0 0 1 0 0 0 1 0 -3 0 +"Tool Open End Wrench" "55299.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Tool Open End Wrench with 3-Rib Handle" "604551.DAT" 0 1 0 0 0 1 0 0 0 1 0 -2 0 +"Tool Pickaxe" "3841.dat" 0 1 0 0 0 1 0 0 0 1 0 -12 0 +"Tool Power Drill" "55297.dat" 0 1 0 0 0 1 0 0 0 1 0 -6 0 +"Tool Screwdriver" "55298.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Tool Screwdriver with Wide Head and 3-Rib Handle" "604550.DAT" 0 1 0 0 0 1 0 0 0 1 0 -2 0 +"Tool Socket Wrench with Ratchet and 3-Rib Handle" "604615.DAT" 0 1 0 0 0 1 0 0 0 1 0 -2 0 +"Tool Spanner/Screwdriver" "4006.dat" 0 0 0 -1 0 1 0 1 0 0 0 -14 0 +"Toolbox 1 x 3 with Handle" "98368.dat" 0 0 0 1 -1 0 0 0 -1 0 0 -2 0 +"Torch" "3959.dat" 0 1 0 0 0 1 0 0 0 1 0 -13 0 +"Torch without Grooves" "86208.dat" 0 1 0 0 0 1 0 0 0 1 0 -13 0 +"Toy Winder Key" "98375.dat" 0 0 0 -1 1 0 0 0 -1 0 0 -2 -20 +"Tray Oval" "11252.dat" 0 0 1 0 -1 0 0 0 0 1 6 -3 -16 +"Underwater Scooter" "30092.dat" 0 -1 0 0 0 1 0 0 0 -1 -20 -22 -8.5 +"Weapon Billy Club" "13790.DAT" 0 1 0 0 0 1 0 0 0 1 0 -7.5 0 +"Weapon Bladed Claw" "88811.dat" 0 1 0 0 0 1 0 0 0 1 0 2 0 +"Weapon Club with Spikes" "88001.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Weapon Crescent Blade Serrated with Bar 0.5L" "98141.dat" 0 1 0 0 0 1 0 0 0 1 0 2 0 +"Weapon Curved Blade 8.5L with Bar 1.5L" "98137.dat" 0 1 0 0 0 1 0 0 0 1 0 12 0 +"Weapon Hand Dagger" "88812.dat" 0 1 0 0 0 1 0 0 0 1 0 2 0 +"Weapon Trident" "92290.dat" 0 1 0 0 0 1 0 0 0 1 0 24 0 +"Welding Gas Torch with Hose and Gas Cylinder Top" "13793.DAT" 0 1 0 0 0 1 0 0 0 1 30 35 0 +"Whip" "2488.dat" 0 1 0 0 0 1 0 0 0 1 0 -8 0 +"Whip in Latched Position (Shortcut)" "2488c01.dat" 0 1 0 0 0 1 0 0 0 1 0 -8 0 +"Whip Coiled" "61975.dat" 0 0 0 -1 0 1 0 1 0 0 0 -8 0 +"Wine Glass" "33061.dat" 0 1 0 0 0 1 0 0 0 1 0 -32 0 +"Zip Line Handle" "30229.dat" 0 1 0 0 0 1 0 0 0 1 0 -12 0 + + + +[LLEG] +"Plain Leg" "3816.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"3 Black Diamonds Pattern" "3816pba.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Astro Pattern" "3816P6F.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Blue/White Triangles, Fringe Pattern" "3816PW2.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Buttoned Pocket Pattern" "3816PA3.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Chainlink and 3 Safety Pins Pattern" "3816PC44.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Clockwork Robot Pattern" "3816PC67.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"DarkBlue Loincloth Pattern" "3816PQ0.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"DarkBlue and Gold Loincloth Pattern" "3816PQ1.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"DarkRed Loincloth, White Claws and Fur Tail Pattern" "3816PAW.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"DarkTurquoise/White Triangles, White Fringe Pattern" "3816PW3.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Golden Circuit Pattern" "3816P6W.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Grass Skirt Pattern" "3816p3j.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Green Kilt and Toes Pattern" "3816pa2.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Holster and Belt Pattern" "3816PA9.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Iron Man Armoured Suit Mark VI Pattern" "3816PBB.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Iron Man Armoured Suit Mark VII Pattern" "3816PBC.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Iron Man Armoured Suit Mark XLII Pattern" "3816PBF.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Iron Man Armoured Suit Mark XVII Pattern" "3816PBE.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Iron Patriot Armoured Suit Kneepad Pattern" "3816PBG.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Laboratory Smock Pattern" "3816PDE.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Leather Straps (Red Studs) Pattern" "3816p4f.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"LOTR Coat and Shirttails Pattern" "3816PM2.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"LOTR Leather Armor Pattern" "3816PM0.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"LOTR Scale Armor Pattern" "3816PM1.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Orange Cable Pattern" "3816P6u.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Purple Greatcoat Pattern" "3816phb.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Red/White Triangles Pattern" "3816PW1.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 + +; Update 2015-01 +"Reflective Stripe Pattern" "3816P8H.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Reflective Stripe and Triangles on Feet Pattern" "3816P8I.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 + +"Robot Pattern" "3816P63.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Salmon Cable Pattern" "3816P6V.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"SW Gunbelt Pattern" "3816ps5.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"SW Stormtrooper Pattern" "3816PSK.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"SW White Leggings Pattern" "3816PS0.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"War Machine Armoured Suit Kneepad Pattern" "3816PBD.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"White Apron Pattern" "3816P89.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 + +; Update 2015-01 +"White and Gold Markings Pattern" "3816P6G.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 + + +"--------------------Non-standard legs-------------------------------------------" "" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Leg Skeleton" "6266.DAT" 0 1 0 0 0 1 0 0 0 1 -10 0 0 +"Leg Wooden" "2532.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Mechanical Leg" "53984.DAT" 0 1 0 0 0 1 0 0 0 1 -10 44 -10 +"--------------------------------------------------------------------------------" "" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Hips and Legs Short -> Hips:" "" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Legs Old -> Hips:" "" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Mechanical Legs -> Hips:" "" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Skirts (Slope Brick 65 2 x 2 x 2) -> Hips:" "" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"--------------------------------------------------------------------------------" "" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"None" "" 0 1 0 0 0 1 0 0 0 1 0 0 0 + + + +[RLEG] +"Plain Leg" "3817.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"2 Red Diamonds Pattern" "3817PBA.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"2 Safety Pins Pattern" "3817PC44.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Astro Pattern" "3817P6F.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Blue/White Triangles, Fringe Pattern" "3817PW2.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Buttoned Pocket Pattern" "3817PA3.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Clockwork Robot Pattern" "3817PC67.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"DarkBlue Loincloth Pattern" "3817PQ0.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"DarkBlue and Gold Loincloth Pattern" "3817PQ1.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"DarkRed Loincloth and White Claws Pattern" "3817PAW.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"DarkTurquoise/White Triangles, White Fringe Pattern" "3817PW3.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 + +; Update 2015-01 +"'EMMET' Badge, Reflective Stripe Pattern" "3817P8H.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"'EMMET' Badge, Reflective Stripe, Silver Triangles Pattern""3817P8I.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 + +"Golden Circuit Pattern" "3817P6W.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Grass Skirt Pattern" "3817p3j.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Green Kilt and Toes Pattern" "3817pa2.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Holster and Belt Pattern" "3817PA9.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Iron Man Armoured Suit Mark VI Pattern" "3817PBB.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Iron Man Armoured Suit Mark VII Pattern" "3817PBC.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Iron Man Armoured Suit Mark XLII Pattern" "3817PBF.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Iron Man Armoured Suit Mark XVII Pattern" "3817PBE.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Iron Patriot Armoured Suit Kneepad Pattern" "3817PBG.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Laboratory Smock Pattern" "3817PDE.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Leather Straps (Red Studs) Pattern" "3817p4f.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"LOTR Coat and Shirttails Pattern" "3817PM2.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"LOTR Leather Armor Pattern" "3817PM0.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"LOTR Scale Armor Pattern" "3817PM1.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Orange Cable Pattern" "3817P6u.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Purple Greatcoat Pattern" "3817phb.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Red/White Triangles Pattern" "3817PW1.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Robot Pattern" "3817P63.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Salmon Cable Pattern" "3817P6V.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"SW Stormtrooper Pattern" "3817PSK.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"SW White Leggings Pattern" "3817PS0.dat" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"War Machine Armoured Suit Kneepad Pattern" "3817PBD.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"White Apron Pattern" "3817P89.DAT" 0 1 0 0 0 1 0 0 0 1 0 0 0 + +"--------------------Non-standard legs-------------------------------------------" "" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Leg Wooden" "2532.DAT" 0 -1 0 0 0 1 0 0 0 -1 0 0 0 +"Leg Skeleton" "6266.DAT" 0 1 0 0 0 1 0 0 0 1 10 0 0 +"Mechanical Leg" "53984.DAT" 0 1 0 0 0 1 0 0 0 1 10 44 -10 +"--------------------------------------------------------------------------------" "" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Hips and Legs Short -> Hips:" "" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Legs Old -> Hips:" "" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Mechanical Legs -> Hips:" "" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Skirts (Slope Brick 65 2 x 2 x 2) -> Hips:" "" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"--------------------------------------------------------------------------------" "" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"None" "" 0 1 0 0 0 1 0 0 0 1 0 0 0 + + + +[LLEGA] +"None" "" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"--------------------------------------------------------------------------------" "" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Flipper" "2599.DAT" 0 0.996 0 0.087 0 1 0 -0.087 0 0.996 -10 28 -1 +"Roller Skate" "11253.DAT" 0 1 0 0 0 1 0 0 0 1 -10 28 -1 +"Skate" "93555.DAT" 0 1 0 0 0 1 0 0 0 1 -10 28 -1 +"Skateboard with Black Wheels (Shortcut)" "42511c01.DAT" 0 1 0 0 0 1 0 0 0 1 0 28 1 +"Snowshoe" "30284.DAT" 0 1 0 0 0 1 0 0 0 1 -10 28 -1 +"Ski" "6120.DAT" 0 1 0 0 0 1 0 0 0 1 -10 28 1 + +; Update 2015-01 +"Ski 4L without Hinge" "99774.DAT" 0 1 0 0 0 1 0 0 0 1 -10 28 -1 + +"Ski 6L" "90509.DAT" 0 1 0 0 0 1 0 0 0 1 -10 28 -1 +"--------------------Non-standard accessories------------------------------------" "" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Plate 2x4 with Curved Beveled Sides" "88000.DAT" 0 1 0 0 0 1 0 0 0 1 0 28 0 +"Surf Board 2 x 6.5" "90397.DAT" 0 0 0 1 0 1 0 -1 0 0 0 28 -1 +"Surf Board 2 x 6.5 with Pink Flames Pattern" "90397P02.DAT" 0 0 0 1 0 1 0 -1 0 0 0 28 -1 +"Surf Board 2 x 10" "6075.DAT" 0 -1 0 0 0 1 0 0 0 -1 0 28 -1 + + +[RLEGA] +"None" "" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"--------------------------------------------------------------------------------" "" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Flipper" "2599.DAT" 0 0.996 0 -0.087 0 1 0 0.087 0 0.996 10 28 -1 +"Roller Skate" "11253.DAT" 0 1 0 0 0 1 0 0 0 1 10 28 -1 +"Skate" "93555.DAT" 0 1 0 0 0 1 0 0 0 1 10 28 -1 +"Skateboard with Black Wheels (Shortcut)" "42511c01.DAT" 0 1 0 0 0 1 0 0 0 1 0 28 1 +"Snowshoe" "30284.DAT" 0 1 0 0 0 1 0 0 0 1 10 28 -1 +"Ski" "6120.dat" 0 1 0 0 0 1 0 0 0 1 10 28 1 + +; Update 2015-01 +"Ski 4L without Hinge" "99774.DAT" 0 1 0 0 0 1 0 0 0 1 10 28 -1 + +"Ski 6L" "90509.DAT" 0 1 0 0 0 1 0 0 0 1 10 28 -1 +"--------------------Non-standard accessories------------------------------------" "" 0 1 0 0 0 1 0 0 0 1 0 0 0 +"Plate 2x4 with Curved Beveled Sides" "88000.DAT" 0 1 0 0 0 1 0 0 0 1 0 28 0 +"Surf Board 2 x 6.5" "90397.DAT" 0 0 0 -1 0 1 0 1 0 0 0 28 -1 +"Surf Board 2 x 6.5 with Pink Flames Pattern" "90397P02.DAT" 0 0 0 -1 0 1 0 1 0 0 0 28 -1 +"Surf Board 2 x 10" "6075.DAT" 0 -1 0 0 0 1 0 0 0 -1 0 28 -1