Added option to draw studs on the base grid.

This commit is contained in:
leo 2013-08-31 21:58:47 +00:00
parent 7dfac75de5
commit 8609014e64
17 changed files with 652 additions and 244 deletions

View file

@ -2,87 +2,118 @@
#include "image.h"
#include "opengl.h"
Image::Image ()
Image::Image()
{
mData = NULL;
mWidth = 0;
mHeight = 0;
mAlpha = false;
mFormat = LC_PIXEL_FORMAT_INVALID;
}
Image::~Image ()
Image::~Image()
{
FreeData();
}
void Image::FreeData ()
int Image::GetBPP() const
{
switch (mFormat)
{
case LC_PIXEL_FORMAT_INVALID:
return 0;
case LC_PIXEL_FORMAT_A8:
return 1;
case LC_PIXEL_FORMAT_L8A8:
return 2;
case LC_PIXEL_FORMAT_R8G8B8:
return 3;
case LC_PIXEL_FORMAT_R8G8B8A8:
return 4;
}
return 0;
}
bool Image::HasAlpha() const
{
switch (mFormat)
{
case LC_PIXEL_FORMAT_INVALID:
return false;
case LC_PIXEL_FORMAT_A8:
return true;
case LC_PIXEL_FORMAT_L8A8:
return true;
case LC_PIXEL_FORMAT_R8G8B8:
return false;
case LC_PIXEL_FORMAT_R8G8B8A8:
return true;
}
return 0;
}
void Image::FreeData()
{
free(mData);
mData = NULL;
mWidth = 0;
mHeight = 0;
mAlpha = false;
mFormat = LC_PIXEL_FORMAT_INVALID;
}
void Image::Allocate(int Width, int Height, bool Alpha)
void Image::Allocate(int Width, int Height, lcPixelFormat Format)
{
FreeData ();
FreeData();
mWidth = Width;
mHeight = Height;
mAlpha = Alpha;
if (mAlpha)
mData = (unsigned char*)malloc(mWidth * mHeight * 4);
else
mData = (unsigned char*)malloc(mWidth * mHeight * 3);
mFormat = Format;
mData = (unsigned char*)malloc(mWidth * mHeight * GetBPP());
}
void Image::ResizePow2 ()
void Image::ResizePow2()
{
int i, shifted_x, shifted_y;
int i, shifted_x, shifted_y;
shifted_x = mWidth;
for (i = 0; ((i < 16) && (shifted_x != 0)); i++)
shifted_x = shifted_x >> 1;
shifted_x = (i != 0) ? 1 << (i-1) : 1;
for (i = 0; ((i < 16) && (shifted_x != 0)); i++)
shifted_x = shifted_x >> 1;
shifted_x = (i != 0) ? 1 << (i-1) : 1;
shifted_y = mHeight;
for (i = 0; ((i < 16) && (shifted_y != 0)); i++)
shifted_y = shifted_y >> 1;
shifted_y = (i != 0) ? 1 << (i-1) : 1;
for (i = 0; ((i < 16) && (shifted_y != 0)); i++)
shifted_y = shifted_y >> 1;
shifted_y = (i != 0) ? 1 << (i-1) : 1;
if ((shifted_x != mWidth) || (shifted_y != mHeight))
Resize (shifted_x, shifted_y);
Resize (shifted_x, shifted_y);
}
void Image::Resize (int width, int height)
void Image::Resize(int width, int height)
{
int i, j, k, components, stx, sty;
float accumx, accumy;
unsigned char* bits;
int i, j, k, components, stx, sty;
float accumx, accumy;
unsigned char* bits;
if (mAlpha)
components = 4;
else
components = 3;
components = GetBPP();
bits = (unsigned char*)malloc (width * height * components);
bits = (unsigned char*)malloc(width * height * components);
for (j = 0; j < mHeight; j++)
{
{
accumy = (float)height*j/(float)mHeight;
sty = (int)floor(accumy);
sty = (int)floor(accumy);
for (i = 0; i < mWidth; i++)
{
{
accumx = (float)width*i/(float)mWidth;
stx = (int)floor(accumx);
stx = (int)floor(accumx);
for (k = 0; k < components; k++)
for (k = 0; k < components; k++)
bits[(stx+sty*width)*components+k] = mData[(i+j*mWidth)*components+k];
}
}
}
}
free (mData);
mData = bits;
@ -92,11 +123,11 @@ void Image::Resize (int width, int height)
void Image::FromOpenGL(int Width, int Height)
{
Allocate(Width, Height, true);
Allocate(Width, Height, LC_PIXEL_FORMAT_R8G8B8A8);
lcuint8* Buffer = (lcuint8*)malloc(Width * Height * 4);
glPixelStorei (GL_PACK_ALIGNMENT, 1);
glPixelStorei (GL_PACK_ALIGNMENT, 1);
glReadPixels(0, 0, Width, Height, GL_RGBA, GL_UNSIGNED_BYTE, Buffer);
for (int Row = 0; Row < Height; Row++)

View file

@ -14,12 +14,24 @@ enum LC_IMAGE_FORMAT
LC_IMAGE_PNG
};
enum lcPixelFormat
{
LC_PIXEL_FORMAT_INVALID,
LC_PIXEL_FORMAT_A8,
LC_PIXEL_FORMAT_L8A8,
LC_PIXEL_FORMAT_R8G8B8,
LC_PIXEL_FORMAT_R8G8B8A8
};
class Image
{
public:
Image();
virtual ~Image();
int GetBPP() const;
bool HasAlpha() const;
bool FileSave(lcMemFile& File, LC_IMAGE_FORMAT Format, bool Transparent) const;
bool FileSave(const char* FileName, LC_IMAGE_FORMAT Format, bool Transparent) const;
bool FileLoad(lcMemFile& File);
@ -28,12 +40,12 @@ public:
void Resize(int Width, int Height);
void ResizePow2();
void FromOpenGL(int Width, int Height);
void Allocate(int Width, int Height, bool Alpha);
void Allocate(int Width, int Height, lcPixelFormat Format);
void FreeData();
int mWidth;
int mHeight;
bool mAlpha;
lcPixelFormat mFormat;
unsigned char* mData;
};

View file

@ -151,7 +151,11 @@ struct lcPreferencesDialogOptions
lcuint32 Detail;
float LineWidth;
int AASamples;
int GridSize;
bool GridStuds;
lcuint32 GridStudColor;
bool GridLines;
int GridLineSpacing;
lcuint32 GridLineColor;
lcArray<lcLibraryCategory> Categories;
bool CategoriesModified;

View file

@ -9,7 +9,12 @@
#define LC_PI 3.141592f
#define LC_2PI 6.283185f
#define LC_RGB(r,g,b) ((lcuint32)(((lcuint8) (r) | ((lcuint16) (g) << 8))|(((lcuint32) (lcuint8) (b)) << 16)))
#define LC_RGB(r,g,b) LC_RGBA(r,g,b,255)
#define LC_RGBA(r,g,b,a) ((lcuint32)(((lcuint8) (r) | ((lcuint16) (g) << 8)) | (((lcuint32) (lcuint8) (b)) << 16) | (((lcuint32) (lcuint8) (a)) << 24)))
#define LC_RGBA_RED(rgba) ((lcuint8)(((rgba) >> 0) & 0xff))
#define LC_RGBA_GREEN(rgba) ((lcuint8)(((rgba) >> 8) & 0xff))
#define LC_RGBA_BLUE(rgba) ((lcuint8)(((rgba) >> 16) & 0xff))
#define LC_RGBA_ALPHA(rgba) ((lcuint8)(((rgba) >> 24) & 0xff))
#define LC_FLOATRGB(f) LC_RGB(f[0]*255, f[1]*255, f[2]*255)
template <typename T, typename U>
@ -442,6 +447,13 @@ inline lcVector4& operator/=(lcVector4& a, float b)
return a;
}
inline lcVector4 lcVector4FromColor(lcuint32 Color)
{
lcVector4 v(LC_RGBA_RED(Color), LC_RGBA_GREEN(Color), LC_RGBA_BLUE(Color), LC_RGBA_ALPHA(Color));
v /= 255.0f;
return v;
}
inline lcVector3 lcMul31(const lcVector3& a, const lcMatrix44& b)
{
lcVector4 v = b.r[0] * a[0] + b.r[1] * a[1] + b.r[2] * a[2] + b.r[3];

View file

@ -49,7 +49,11 @@ lcProfileEntry gProfileEntries[LC_NUM_PROFILE_KEYS] =
lcProfileEntry("Settings", "Snap", LC_DRAW_SNAP_A | LC_DRAW_SNAP_XYZ), // LC_PROFILE_SNAP
lcProfileEntry("Settings", "AngleSnap", 30), // LC_PROFILE_ANGLE_SNAP
lcProfileEntry("Settings", "LineWidth", 1.0f), // LC_PROFILE_LINE_WIDTH
lcProfileEntry("Settings", "GridSize", 20), // LC_PROFILE_GRID_SIZE
lcProfileEntry("Settings", "GridStuds", 1), // LC_PROFILE_GRID_STUDS
lcProfileEntry("Settings", "GridStudColor", LC_RGBA(64, 64, 64, 128)), // LC_PROFILE_GRID_STUD_COLOR
lcProfileEntry("Settings", "GridLines", 1), // LC_PROFILE_GRID_LINES
lcProfileEntry("Settings", "GridLineSpacing", 5), // LC_PROFILE_GRID_LINE_SPACING
lcProfileEntry("Settings", "GridLineColor", LC_RGBA(0, 0, 0, 255)), // LC_PROFILE_GRID_LINE_COLOR
lcProfileEntry("Settings", "AASamples", 1), // LC_PROFILE_ANTIALIASING_SAMPLES
lcProfileEntry("Settings", "CheckUpdates", 1), // LC_PROFILE_CHECK_UPDATES

View file

@ -8,7 +8,11 @@ enum LC_PROFILE_KEY
LC_PROFILE_SNAP,
LC_PROFILE_ANGLE_SNAP,
LC_PROFILE_LINE_WIDTH,
LC_PROFILE_GRID_SIZE,
LC_PROFILE_GRID_STUDS,
LC_PROFILE_GRID_STUD_COLOR,
LC_PROFILE_GRID_LINES,
LC_PROFILE_GRID_LINE_SPACING,
LC_PROFILE_GRID_LINE_COLOR,
LC_PROFILE_ANTIALIASING_SAMPLES,
LC_PROFILE_CHECK_UPDATES,

View file

@ -41,51 +41,80 @@ bool lcTexture::Load(lcMemFile& File, int Flags)
return Load(image, Flags);
}
bool lcTexture::Load(Image& image, int Flags)
bool lcTexture::Load(Image* images, int NumLevels, int Flags)
{
image.ResizePow2();
mWidth = image.mWidth;
mHeight = image.mHeight;
mWidth = images[0].mWidth;
mHeight = images[0].mHeight;
glGenTextures(1, &mTexture);
int Filters[2][5] =
{
{ GL_NEAREST_MIPMAP_NEAREST, GL_NEAREST_MIPMAP_LINEAR, GL_LINEAR_MIPMAP_NEAREST, GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR_MIPMAP_LINEAR },
{ GL_NEAREST, GL_LINEAR, GL_LINEAR, GL_LINEAR, GL_LINEAR },
};
int FilterFlags = Flags & LC_TEXTURE_FILTER_MASK;
int FilterIndex = FilterFlags >> LC_TEXTURE_FILTER_SHIFT;
int MipIndex = Flags & LC_TEXTURE_MIPMAPS ? 0 : 1;
glBindTexture(GL_TEXTURE_2D, mTexture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, (Flags & LC_TEXTURE_WRAPU) ? GL_REPEAT : GL_CLAMP);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, (Flags & LC_TEXTURE_WRAPV) ? GL_REPEAT : GL_CLAMP);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, (Flags & LC_TEXTURE_MIPMAPS) ? GL_LINEAR_MIPMAP_NEAREST : GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, Filters[MipIndex][FilterIndex]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, Filters[1][FilterIndex]);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
int Format = image.mAlpha ? GL_RGBA : GL_RGB;
void* Data = image.mData;
if (GL_SupportsAnisotropic && FilterFlags == LC_TEXTURE_ANISOTROPIC)
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, lcMin(4.0f, GL_MaxAnisotropy));
glTexImage2D(GL_TEXTURE_2D, 0, image.mAlpha ? GL_RGBA : GL_RGB, mWidth, mHeight, 0, Format, GL_UNSIGNED_BYTE, Data);
int Format;
switch (images[0].mFormat)
{
case LC_PIXEL_FORMAT_A8:
Format = GL_ALPHA;
break;
case LC_PIXEL_FORMAT_L8A8:
Format = GL_LUMINANCE_ALPHA;
break;
case LC_PIXEL_FORMAT_R8G8B8:
Format = GL_RGB;
break;
case LC_PIXEL_FORMAT_R8G8B8A8:
Format = GL_RGBA;
break;
}
void* Data = images[0].mData;
glTexImage2D(GL_TEXTURE_2D, 0, Format, mWidth, mHeight, 0, Format, GL_UNSIGNED_BYTE, Data);
if (Flags & LC_TEXTURE_MIPMAPS)
{
int Width = mWidth;
int Height = mHeight;
int Components = (Format == GL_RGBA) ? 4 : 3;
int Components = images[0].GetBPP();
for (int Level = 1; ((Width != 1) || (Height != 1)); Level++)
{
GLubyte *Out, *In;
int RowStride = Width * Components;
Width = lcMax(1, Width >> 1);
Height = lcMax(1, Height >> 1);
In = Out = (GLubyte*)Data;
if (NumLevels == 1)
{
GLubyte *Out, *In;
int RowStride = Width * Components;
for (int y = 0; y < Height; y++, In += RowStride)
for (int x = 0; x < Width; x++, Out += Components, In += 2 * Components)
for (int c = 0; c < Components; c++)
Out[c] = (In[c] + In[c + Components] + In[RowStride] + In[c + RowStride + Components]) / 4;
In = Out = (GLubyte*)Data;
glTexImage2D(GL_TEXTURE_2D, Level, Components, Width, Height, 0, Format, GL_UNSIGNED_BYTE, Data);
for (int y = 0; y < Height; y++, In += RowStride)
for (int x = 0; x < Width; x++, Out += Components, In += 2 * Components)
for (int c = 0; c < Components; c++)
Out[c] = (In[c] + In[c + Components] + In[RowStride] + In[c + RowStride + Components]) / 4;
}
else
Data = images[Level].mData;
glTexImage2D(GL_TEXTURE_2D, Level, Format, Width, Height, 0, Format, GL_UNSIGNED_BYTE, Data);
}
}
@ -94,6 +123,13 @@ bool lcTexture::Load(Image& image, int Flags)
return true;
}
bool lcTexture::Load(Image& image, int Flags)
{
image.ResizePow2();
return Load(&image, 1, Flags);
}
void lcTexture::Unload()
{
if (mTexture)

View file

@ -3,9 +3,17 @@
#include "opengl.h"
#define LC_TEXTURE_WRAPU 0x01
#define LC_TEXTURE_WRAPV 0x02
#define LC_TEXTURE_MIPMAPS 0x04
#define LC_TEXTURE_WRAPU 0x01
#define LC_TEXTURE_WRAPV 0x02
#define LC_TEXTURE_MIPMAPS 0x04
#define LC_TEXTURE_POINT 0x00
#define LC_TEXTURE_LINEAR 0x10
#define LC_TEXTURE_BILINEAR 0x20
#define LC_TEXTURE_TRILINEAR 0x30
#define LC_TEXTURE_ANISOTROPIC 0x40
#define LC_TEXTURE_FILTER_MASK 0xf0
#define LC_TEXTURE_FILTER_SHIFT 4
#define LC_TEXTURE_NAME_LEN 256
@ -20,6 +28,7 @@ public:
bool Load(const char* FileName, int Flags = 0);
bool Load(lcMemFile& File, int Flags = 0);
bool Load(Image& image, int Flags);
bool Load(Image* images, int NumLevels, int Flags);
void Unload();
int AddRef()

View file

@ -42,6 +42,8 @@ GLFRAMEBUFFERTEXTURELAYERARBPROC lcFramebufferTextureLayerARB;
bool GL_SupportsVertexBufferObject;
bool GL_UseVertexBufferObject;
bool GL_SupportsFramebufferObject;
bool GL_SupportsAnisotropic;
GLfloat GL_MaxAnisotropy;
bool GL_ExtensionSupported(const GLubyte* Extensions, const char* Name)
{
@ -76,6 +78,13 @@ void GL_InitializeSharedExtensions(lcGLWidget* Window)
{
const GLubyte* Extensions = glGetString(GL_EXTENSIONS);
if (GL_ExtensionSupported(Extensions, "GL_EXT_texture_filter_anisotropic"))
{
glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &GL_MaxAnisotropy);
GL_SupportsAnisotropic = true;
}
if (GL_ExtensionSupported(Extensions, "GL_ARB_vertex_buffer_object"))
{
lcBindBufferARB = (GLBINDBUFFERARBPROC)Window->GetExtensionAddress("glBindBufferARB");

View file

@ -9,6 +9,8 @@ bool GL_ExtensionSupported(const GLubyte* Extensions, const char* Name);
extern bool GL_SupportsVertexBufferObject;
extern bool GL_UseVertexBufferObject;
extern bool GL_SupportsFramebufferObject;
extern bool GL_SupportsAnisotropic;
extern GLfloat GL_MaxAnisotropy;
inline void GL_DisableVertexBufferObject()
{
@ -88,6 +90,11 @@ typedef ptrdiff_t GLintptrARB;
typedef ptrdiff_t GLsizeiptrARB;
#endif
#ifndef GL_EXT_texture_filter_anisotropic
#define GL_TEXTURE_MAX_ANISOTROPY_EXT 0x84FE
#define GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT 0x84FF
#endif
#ifndef GL_ARB_vertex_buffer_object
#define GL_BUFFER_SIZE_ARB 0x8764
#define GL_BUFFER_USAGE_ARB 0x8765

View file

@ -47,12 +47,12 @@ Project::Project()
m_pGroups = NULL;
m_pUndoList = NULL;
m_pRedoList = NULL;
m_nGridList = 0;
m_pTrackFile = NULL;
m_nCurAction = 0;
mTransformType = LC_TRANSFORM_RELATIVE_TRANSLATION;
m_pTerrain = new Terrain();
m_pBackground = new lcTexture();
mGridTexture = new lcTexture();
m_nAutosave = lcGetProfileInt(LC_PROFILE_AUTOSAVE_INTERVAL);
m_nMouse = lcGetProfileInt(LC_PROFILE_MOUSE_SENSITIVITY);
m_nDownX = 0;
@ -69,6 +69,7 @@ Project::~Project()
delete m_pTrackFile;
delete m_pTerrain;
delete m_pBackground;
delete mGridTexture;
delete m_pScreenFont;
}
@ -222,7 +223,11 @@ void Project::LoadDefaults(bool cameras)
m_fFogColor[1] = (float)((unsigned char) (((unsigned short) (rgb)) >> 8))/255;
m_fFogColor[2] = (float)((unsigned char) ((rgb) >> 16))/255;
m_fFogColor[3] = 1.0f;
m_nGridSize = (unsigned short)lcGetProfileInt(LC_PROFILE_GRID_SIZE);
mGridStuds = lcGetProfileInt(LC_PROFILE_GRID_STUDS);
mGridStudColor = lcGetProfileInt(LC_PROFILE_GRID_STUD_COLOR);
mGridLines = lcGetProfileInt(LC_PROFILE_GRID_LINES);
mGridLineSpacing = lcGetProfileInt(LC_PROFILE_GRID_LINE_SPACING);
mGridLineColor = lcGetProfileInt(LC_PROFILE_GRID_LINE_COLOR);
rgb = lcGetProfileInt(LC_PROFILE_DEFAULT_AMBIENT_COLOR);
m_fAmbient[0] = (float)((unsigned char) (rgb))/255;
m_fAmbient[1] = (float)((unsigned char) (((unsigned short) (rgb)) >> 8))/255;
@ -646,7 +651,7 @@ bool Project::FileLoad(lcFile* file, bool bUndo, bool bMerge)
file->ReadU8(&m_nFPS, 1);
file->ReadS32(&i, 1); m_nCurFrame = i;
file->ReadU16(&m_nTotalFrames, 1);
file->ReadS32(&i, 1); m_nGridSize = i;
file->ReadS32(&i, 1); //m_nGridSize = i;
file->ReadS32(&i, 1); //m_nMoveSnap = i;
}
else
@ -656,7 +661,7 @@ bool Project::FileLoad(lcFile* file, bool bUndo, bool bMerge)
file->ReadU8(&m_nFPS, 1);
file->ReadU16(&m_nCurFrame, 1);
file->ReadU16(&m_nTotalFrames, 1);
file->ReadU16(&m_nGridSize, 1);
file->ReadU16(&sh, 1); // m_nGridSize = sh;
file->ReadU16(&sh, 1);
if (fv >= 1.4f)
m_nMoveSnap = sh;
@ -827,7 +832,7 @@ void Project::FileSave(lcFile* file, bool bUndo)
file->WriteU8 (&m_nFPS, 1);
file->WriteU16(&m_nCurFrame, 1);
file->WriteU16(&m_nTotalFrames, 1);
file->WriteU16(&m_nGridSize, 1);
file->WriteU16(0); // m_nGridSize
file->WriteU16(&m_nMoveSnap, 1);
// 0.62 (1.1)
rgb = LC_FLOATRGB(m_fGradient1);
@ -1667,12 +1672,6 @@ void Project::RenderScenePieces(View* view)
float AspectRatio = (float)view->mWidth / (float)view->mHeight;
view->mCamera->LoadProjection(AspectRatio);
if (m_nSnap & LC_DRAW_GRID)
{
glColor4f(1.0f - m_fBackground[0], 1.0f - m_fBackground[1], 1.0f - m_fBackground[2], 1.0f);
glCallList (m_nGridList);
}
if (m_nDetail & LC_DET_LIGHTING)
{
glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT);
@ -2064,6 +2063,104 @@ void Project::RenderSceneObjects(View* view)
if (pLight->IsVisible ())
pLight->Render(m_fLineWidth);
if (mGridStuds || mGridLines)
{
float m_nGridSize = 20;
if (mGridLines)
{
float Left = -m_nGridSize*0.8f;
float Right = m_nGridSize*0.8f;
float Top = -m_nGridSize*0.8f;
float Bottom = m_nGridSize*0.8f;
float Z = 0;
float U = m_nGridSize * 2;
float V = m_nGridSize * 2;
float Verts[4 * 5];
float* CurVert = Verts;
*CurVert++ = Left;
*CurVert++ = Top;
*CurVert++ = Z;
*CurVert++ = 0.0f;
*CurVert++ = V;
*CurVert++ = Left;
*CurVert++ = Bottom;
*CurVert++ = Z;
*CurVert++ = 0.0f;
*CurVert++ = 0.0f;
*CurVert++ = Right;
*CurVert++ = Bottom;
*CurVert++ = Z;
*CurVert++ = U;
*CurVert++ = 0.0f;
*CurVert++ = Right;
*CurVert++ = Top;
*CurVert++ = Z;
*CurVert++ = U;
*CurVert++ = V;
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
glBindTexture(GL_TEXTURE_2D, mGridTexture->mTexture);
glEnable(GL_TEXTURE_2D);
glEnable(GL_ALPHA_TEST);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_BLEND);
glColor4fv(lcVector4FromColor(mGridStudColor));
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(3, GL_FLOAT, 5 * sizeof(float), Verts);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glTexCoordPointer(2, GL_FLOAT, 5 * sizeof(float), Verts + 3);
glDrawArrays(GL_QUADS, 0, 4);
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glDisable(GL_TEXTURE_2D);
glDisable(GL_BLEND);
glDisable(GL_ALPHA_TEST);
}
if (mGridLines)
{
glColor4fv(lcVector4FromColor(mGridLineColor));
glEnableClientState(GL_VERTEX_ARRAY);
int GridStep = 5;
int NumVerts = 2 * 2 * (2 * m_nGridSize / GridStep + 1);
float* Verts = (float*)malloc(NumVerts * sizeof(float[3]));
float x = m_nGridSize * 0.8f;
for (int Step = 0; Step < 2 * m_nGridSize / GridStep + 1; Step++)
{
Verts[Step * 12] = x;
Verts[Step * 12 + 1] = m_nGridSize * 0.8f;
Verts[Step * 12 + 2] = 0;
Verts[Step * 12 + 3] = x;
Verts[Step * 12 + 4] = -m_nGridSize * 0.8f;
Verts[Step * 12 + 5] = 0;
Verts[Step * 12 + 6] = m_nGridSize * 0.8f;
Verts[Step * 12 + 7] = x;
Verts[Step * 12 + 8] = 0;
Verts[Step * 12 + 9] = -m_nGridSize * 0.8f;
Verts[Step * 12 + 10] = x;
Verts[Step * 12 + 11] = 0;
x -= GridStep * 0.8f;
}
glVertexPointer(3, GL_FLOAT, 0, Verts);
glDrawArrays(GL_LINES, 0, NumVerts);
glDisableClientState(GL_VERTEX_ARRAY);
free(Verts);
}
}
// Draw axis icon
if (m_nSnap & LC_DRAW_AXIS)
{
@ -2891,8 +2988,6 @@ void Project::RenderViewports(View* view)
// Initialize OpenGL
void Project::RenderInitialize()
{
int i;
glEnable(GL_POLYGON_OFFSET_FILL);
glPolygonOffset(0.5f, 0.1f);
@ -2916,35 +3011,86 @@ void Project::RenderInitialize()
// AfxMessageBox ("Could not load background");
}
// Grid display list
if (m_nGridList == 0)
m_nGridList = glGenLists(1);
glNewList (m_nGridList, GL_COMPILE);
glEnableClientState(GL_VERTEX_ARRAY);
i = 2*(4*m_nGridSize+2); // verts needed (2*lines)
float *grid = (float*)malloc(i*sizeof(float[3]));
float x = m_nGridSize*0.8f;
for (int j = 0; j <= m_nGridSize*2; j++)
if (!mGridTexture->mTexture)
{
grid[j*12] = x;
grid[j*12+1] = m_nGridSize*0.8f;
grid[j*12+2] = 0;
grid[j*12+3] = x;
grid[j*12+4] = -m_nGridSize*0.8f;
grid[j*12+5] = 0;
grid[j*12+6] = m_nGridSize*0.8f;
grid[j*12+7] = x;
grid[j*12+8] = 0;
grid[j*12+9] = -m_nGridSize*0.8f;
grid[j*12+10] = x;
grid[j*12+11] = 0;
x -= 0.8f;
const int NumLevels = 9;
Image GridImages[NumLevels];
for (int ImageLevel = 0; ImageLevel < NumLevels; ImageLevel++)
{
Image& GridImage = GridImages[ImageLevel];
const int GridSize = 256 >> ImageLevel;
const float Radius1 = (80 >> ImageLevel) * (80 >> ImageLevel);
const float Radius2 = (72 >> ImageLevel) * (72 >> ImageLevel);
GridImage.Allocate(GridSize, GridSize, LC_PIXEL_FORMAT_A8);
lcuint8* BlurBuffer = new lcuint8[GridSize * GridSize];
for (int y = 0; y < GridSize; y++)
{
lcuint8* Pixel = GridImage.mData + y * GridSize;
memset(Pixel, 0, GridSize);
const float y2 = (y - GridSize / 2) * (y - GridSize / 2);
if (Radius1 <= y2)
continue;
if (Radius2 <= y2)
{
int x1 = sqrtf(Radius1 - y2);
for (int x = GridSize / 2 - x1; x < GridSize / 2 + x1; x++)
Pixel[x] = 255;
}
else
{
int x1 = sqrtf(Radius1 - y2);
int x2 = sqrtf(Radius2 - y2);
for (int x = GridSize / 2 - x1; x < GridSize / 2 - x2; x++)
Pixel[x] = 255;
for (int x = GridSize / 2 + x2; x < GridSize / 2 + x1; x++)
Pixel[x] = 255;
}
}
for (int y = 0; y < GridSize - 1; y++)
{
for (int x = 0; x < GridSize - 1; x++)
{
lcuint8 a = GridImage.mData[x + y * GridSize];
lcuint8 b = GridImage.mData[x + 1 + y * GridSize];
lcuint8 c = GridImage.mData[x + (y + 1) * GridSize];
lcuint8 d = GridImage.mData[x + 1 + (y + 1) * GridSize];
BlurBuffer[x + y * GridSize] = (a + b + c + d) / 4;
}
int x = GridSize - 1;
lcuint8 a = GridImage.mData[x + y * GridSize];
lcuint8 c = GridImage.mData[x + (y + 1) * GridSize];
BlurBuffer[x + y * GridSize] = (a + c) / 2;
}
int y = GridSize - 1;
for (int x = 0; x < GridSize - 1; x++)
{
lcuint8 a = GridImage.mData[x + y * GridSize];
lcuint8 b = GridImage.mData[x + 1 + y * GridSize];
BlurBuffer[x + y * GridSize] = (a + b) / 2;
}
int x = GridSize - 1;
BlurBuffer[x + y * GridSize] = GridImage.mData[x + y * GridSize];
memcpy(GridImage.mData, BlurBuffer, GridSize * GridSize);
delete[] BlurBuffer;
}
mGridTexture->Load(GridImages, NumLevels, LC_TEXTURE_WRAPU | LC_TEXTURE_WRAPV | LC_TEXTURE_MIPMAPS | LC_TEXTURE_ANISOTROPIC);
}
glVertexPointer(3, GL_FLOAT, 0, grid);
glDrawArrays(GL_LINES, 0, i);
glEndList();
free(grid);
}
/////////////////////////////////////////////////////////////////////////////
@ -6201,7 +6347,11 @@ void Project::HandleCommand(LC_COMMANDS id)
Options.Snap = m_nSnap;
Options.LineWidth = m_fLineWidth;
Options.AASamples = CurrentAASamples;
Options.GridSize = m_nGridSize;
Options.GridStuds = mGridStuds;
Options.GridStudColor = mGridStudColor;
Options.GridLines = mGridLines;
Options.GridLineSpacing = mGridLineSpacing;
Options.GridLineColor = mGridLineColor;
Options.Categories = gCategories;
Options.CategoriesModified = false;
@ -6221,7 +6371,11 @@ void Project::HandleCommand(LC_COMMANDS id)
m_nSnap = Options.Snap;
m_nDetail = Options.Detail;
m_fLineWidth = Options.LineWidth;
m_nGridSize = Options.GridSize;
mGridStuds = Options.GridStuds;
mGridStudColor = Options.GridStudColor;
mGridLines = Options.GridLines;
mGridLineSpacing = Options.GridLineSpacing;
mGridLineColor = Options.GridLineColor;
lcSetProfileString(LC_PROFILE_DEFAULT_AUTHOR_NAME, Options.DefaultAuthor);
lcSetProfileString(LC_PROFILE_PROJECTS_PATH, Options.ProjectsPath);
@ -6232,7 +6386,11 @@ void Project::HandleCommand(LC_COMMANDS id)
lcSetProfileInt(LC_PROFILE_CHECK_UPDATES, Options.CheckForUpdates);
lcSetProfileInt(LC_PROFILE_SNAP, Options.Snap);
lcSetProfileInt(LC_PROFILE_DETAIL, Options.Detail);
lcSetProfileInt(LC_PROFILE_GRID_SIZE, Options.GridSize);
lcSetProfileInt(LC_PROFILE_GRID_STUDS, Options.GridStuds);
lcSetProfileInt(LC_PROFILE_GRID_STUD_COLOR, Options.GridStudColor);
lcSetProfileInt(LC_PROFILE_GRID_LINES, Options.GridLines);
lcSetProfileInt(LC_PROFILE_GRID_LINE_SPACING, Options.GridLineSpacing);
lcSetProfileInt(LC_PROFILE_GRID_LINE_COLOR, Options.GridLineColor);
lcSetProfileFloat(LC_PROFILE_LINE_WIDTH, Options.LineWidth);
lcSetProfileInt(LC_PROFILE_ANTIALIASING_SAMPLES, Options.AASamples);
@ -6276,7 +6434,7 @@ void Project::HandleCommand(LC_COMMANDS id)
*/
for (int i = 0; i < m_ViewList.GetSize (); i++)
{
{
m_ViewList[i]->MakeCurrent();
RenderInitialize(); // TODO: get rid of RenderInitialize(), most of it can be done once per frame
}
@ -6633,6 +6791,14 @@ void Project::HandleCommand(LC_COMMANDS id)
Info += GL_HasVertexBufferObject() ? "supported" : "not supported";
Info += "\nGL_ARB_framebuffer_object extension: ";
Info += GL_HasFramebufferObject() ? "supported" : "not supported";
Info += "\nGL_EXT_texture_filter_anisotropic extension: ";
if (GL_SupportsAnisotropic)
{
sprintf(Text, "supported (max %d)", (int)GL_MaxAnisotropy);
Info += Text;
}
else
Info += "not supported";
gMainWindow->DoDialog(LC_DIALOG_ABOUT, (char*)Info);
} break;
@ -7213,7 +7379,7 @@ void Project::GetPieceInsertPosition(View* view, int MouseX, int MouseY, lcVecto
lcUnprojectPoints(ClickPoints, 2, ModelView, Projection, Viewport);
lcVector3 Intersection;
if (lcLinePlaneIntersection(&Intersection, ClickPoints[0], ClickPoints[1], lcVector4(0, 0, 1, 0)))
if (lcLinePlaneIntersection(&Intersection, ClickPoints[0], ClickPoints[1], lcVector4(0, 0, 1, m_pCurPiece->m_fDimensions[5])))
{
SnapVector(Intersection);
Position = Intersection;

View file

@ -411,12 +411,17 @@ protected:
lcuint16 m_nCurFrame;
lcuint16 m_nTotalFrames;
bool mGridStuds;
lcuint32 mGridStudColor;
bool mGridLines;
int mGridLineSpacing;
lcuint32 mGridLineColor;
lcuint32 m_nScene;
lcuint32 m_nDetail;
lcuint32 m_nSnap;
lcuint16 m_nMoveSnap;
lcuint16 m_nAngleSnap;
lcuint16 m_nGridSize;
float m_fLineWidth;
float m_fFogDensity;
float m_fFogColor[4];
@ -427,11 +432,11 @@ protected:
char m_strFooter[256];
char m_strHeader[256];
GLuint m_nGridList;
unsigned long m_nAutosave;
unsigned long m_nSaveTimer;
char m_strBackground[LC_MAXPATH];
lcTexture* m_pBackground;
lcTexture* mGridTexture;
protected:
// File load/save implementation.

View file

@ -211,4 +211,6 @@ void TexFont::PrintText(float Left, float Top, float Z, const char* Text) const
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
delete[] Verts;
}

View file

@ -1,34 +1,37 @@
#include "lc_global.h"
#include "image.h"
#include "lc_file.h"
#include "system.h"
static void copyToQImage(const Image& src, QImage& dest, bool transparent)
{
dest = QImage(src.mWidth, src.mWidth, src.mAlpha ? QImage::Format_ARGB32 : QImage::Format_RGB32);
bool alpha = src.HasAlpha();
dest = QImage(src.mWidth, src.mHeight, alpha ? QImage::Format_ARGB32 : QImage::Format_RGB32);
lcuint8* bytes = (lcuint8*)src.mData;
int bpp = src.GetBPP();
if (transparent && src.mAlpha)
LC_ASSERT(src.mFormat == LC_PIXEL_FORMAT_R8G8B8 || src.mFormat == LC_PIXEL_FORMAT_R8G8B8A8);
if (transparent && alpha)
{
for (int y = 0; y < src.mHeight; y++)
{
for (int x = 0; x < src.mWidth; x++)
{
dest.setPixel(x, y, qRgba(bytes[0], bytes[1], bytes[2], bytes[3]));
bytes += 4;
bytes += bpp;
}
}
}
else
{
int pixelSize = src.mAlpha ? 4 : 3;
for (int y = 0; y < src.mHeight; y++)
{
for (int x = 0; x < src.mWidth; x++)
{
dest.setPixel(x, y, qRgb(bytes[0], bytes[1], bytes[2]));
bytes += pixelSize;
bytes += bpp;
}
}
}
@ -36,7 +39,8 @@ static void copyToQImage(const Image& src, QImage& dest, bool transparent)
static void copyFromQImage(const QImage& src, Image& dest)
{
dest.Allocate(src.width(), src.height(), src.hasAlphaChannel());
bool alpha = src.hasAlphaChannel();
dest.Allocate(src.width(), src.height(), alpha ? LC_PIXEL_FORMAT_R8G8B8A8 : LC_PIXEL_FORMAT_R8G8B8);
lcuint8* bytes = (lcuint8*)dest.mData;
@ -50,7 +54,7 @@ static void copyFromQImage(const QImage& src, Image& dest)
*bytes++ = qGreen(pixel);
*bytes++ = qBlue(pixel);
if (dest.mAlpha)
if (alpha)
*bytes++ = qAlpha(pixel);
}
}

View file

@ -15,6 +15,8 @@ lcQPreferencesDialog::lcQPreferencesDialog(QWidget *parent, void *data) :
ui->setupUi(this);
ui->lineWidth->setValidator(new QDoubleValidator());
connect(ui->gridStudColor, SIGNAL(clicked()), this, SLOT(colorClicked()));
connect(ui->gridLineColor, SIGNAL(clicked()), this, SLOT(colorClicked()));
connect(ui->categoriesTree, SIGNAL(itemSelectionChanged()), this, SLOT(updateParts()));
ui->shortcutEdit->installEventFilter(this);
connect(ui->commandList, SIGNAL(currentItemChanged(QTreeWidgetItem*, QTreeWidgetItem*)), this, SLOT(commandChanged(QTreeWidgetItem*)));
@ -41,15 +43,25 @@ lcQPreferencesDialog::lcQPreferencesDialog(QWidget *parent, void *data) :
ui->antiAliasingSamples->setCurrentIndex(0);
ui->edgeLines->setChecked((options->Detail & LC_DET_BRICKEDGES) != 0);
ui->lineWidth->setText(QString::number(options->LineWidth));
ui->baseGrid->setChecked((options->Snap & LC_DRAW_GRID) != 0);
ui->gridUnits->setText(QString::number(options->GridSize));
ui->gridStuds->setChecked(options->GridStuds);
ui->gridLines->setChecked(options->GridLines);
ui->gridLineSpacing->setText(QString::number(options->GridLineSpacing));
ui->axisIcon->setChecked((options->Snap & LC_DRAW_AXIS) != 0);
ui->enableLighting->setChecked((options->Detail & LC_DET_LIGHTING) != 0);
ui->fastRendering->setChecked((options->Detail & LC_DET_FAST) != 0);
QPixmap pix(12, 12);
pix.fill(QColor(LC_RGBA_RED(options->GridStudColor), LC_RGBA_GREEN(options->GridStudColor), LC_RGBA_BLUE(options->GridStudColor)));
ui->gridStudColor->setIcon(pix);
pix.fill(QColor(LC_RGBA_RED(options->GridLineColor), LC_RGBA_GREEN(options->GridLineColor), LC_RGBA_BLUE(options->GridLineColor)));
ui->gridLineColor->setIcon(pix);
on_antiAliasing_toggled();
on_edgeLines_toggled();
on_baseGrid_toggled();
on_gridStuds_toggled();
on_gridLines_toggled();
updateCategories();
ui->categoriesTree->setCurrentItem(ui->categoriesTree->topLevelItem(0));
@ -102,11 +114,9 @@ void lcQPreferencesDialog::accept()
options->LineWidth = ui->lineWidth->text().toFloat();
}
if (ui->baseGrid->isChecked())
{
options->Snap |= LC_DRAW_GRID;
options->GridSize = ui->gridUnits->text().toInt();
}
options->GridStuds = ui->gridStuds->isChecked();
options->GridLines = ui->gridLines->isChecked();
options->GridLineSpacing = ui->gridLineSpacing->text().toInt();
if (ui->axisIcon->isChecked())
options->Snap |= LC_DRAW_AXIS;
@ -158,6 +168,40 @@ void lcQPreferencesDialog::on_lgeoPathBrowse_clicked()
ui->lgeoPathBrowse->setText(QDir::toNativeSeparators(result));
}
void lcQPreferencesDialog::colorClicked()
{
QObject *button = sender();
QString title;
lcuint32 *color = NULL;
QColorDialog::ColorDialogOptions dialogOptions;
if (button == ui->gridStudColor)
{
color = &options->GridStudColor;
title = tr("Select Grid Stud Color");
dialogOptions = QColorDialog::ShowAlphaChannel;
}
else if (button == ui->gridLineColor)
{
color = &options->GridLineColor;
title = tr("Select Grid Line Color");
dialogOptions = 0;
}
QColor oldColor = QColor(LC_RGBA_RED(*color), LC_RGBA_GREEN(*color), LC_RGBA_BLUE(*color), LC_RGBA_ALPHA(*color));
QColor newColor = QColorDialog::getColor(oldColor, this, title, dialogOptions);
if (newColor == oldColor || !newColor.isValid())
return;
*color = LC_RGBA(newColor.red(), newColor.green(), newColor.blue(), newColor.alpha());
QPixmap pix(12, 12);
pix.fill(newColor);
((QToolButton*)button)->setIcon(pix);
}
void lcQPreferencesDialog::on_antiAliasing_toggled()
{
ui->antiAliasingSamples->setEnabled(ui->antiAliasing->isChecked());
@ -168,9 +212,14 @@ void lcQPreferencesDialog::on_edgeLines_toggled()
ui->lineWidth->setEnabled(ui->edgeLines->isChecked());
}
void lcQPreferencesDialog::on_baseGrid_toggled()
void lcQPreferencesDialog::on_gridStuds_toggled()
{
ui->gridUnits->setEnabled(ui->baseGrid->isChecked());
ui->gridStudColor->setEnabled(ui->gridStuds->isChecked());
}
void lcQPreferencesDialog::on_gridLines_toggled()
{
ui->gridLineColor->setEnabled(ui->gridLines->isChecked());
}
void lcQPreferencesDialog::updateCategories()

View file

@ -31,9 +31,11 @@ public slots:
void on_partsLibraryBrowse_clicked();
void on_povrayExecutableBrowse_clicked();
void on_lgeoPathBrowse_clicked();
void colorClicked();
void on_antiAliasing_toggled();
void on_edgeLines_toggled();
void on_baseGrid_toggled();
void on_gridStuds_toggled();
void on_gridLines_toggled();
void updateParts();
void on_newCategory_clicked();
void on_editCategory_clicked();

View file

@ -218,29 +218,165 @@
<attribute name="title">
<string>Rendering</string>
</attribute>
<layout class="QGridLayout" name="gridLayout">
<item row="2" column="0">
<widget class="QCheckBox" name="baseGrid">
<property name="text">
<string>Base grid</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_8">
<item>
<widget class="QWidget" name="widget" native="true">
<layout class="QGridLayout" name="gridLayout">
<item row="4" column="0">
<widget class="QCheckBox" name="fastRendering">
<property name="text">
<string>Fast rendering</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLineEdit" name="lineWidth">
<property name="maximumSize">
<size>
<width>75</width>
<height>16777215</height>
</size>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QCheckBox" name="edgeLines">
<property name="text">
<string>Edge lines</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QCheckBox" name="axisIcon">
<property name="text">
<string>Axis icon</string>
</property>
</widget>
</item>
<item row="1" column="2">
<widget class="QLabel" name="label_2">
<property name="text">
<string>width</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QCheckBox" name="antiAliasing">
<property name="text">
<string>Anti-aliasing</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QCheckBox" name="enableLighting">
<property name="text">
<string>Enable lighting</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QComboBox" name="antiAliasingSamples">
<item>
<property name="text">
<string>2x</string>
</property>
</item>
<item>
<property name="text">
<string>4x</string>
</property>
</item>
<item>
<property name="text">
<string>8x</string>
</property>
</item>
</widget>
</item>
<item row="0" column="3">
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</item>
<item row="0" column="0">
<widget class="QCheckBox" name="antiAliasing">
<property name="text">
<string>Anti-aliasing</string>
<item>
<widget class="QGroupBox" name="groupBox_4">
<property name="title">
<string>Base Grid</string>
</property>
<layout class="QGridLayout" name="gridLayout_2">
<item row="1" column="3">
<widget class="QToolButton" name="gridLineColor">
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLineEdit" name="gridLineSpacing">
<property name="maximumSize">
<size>
<width>75</width>
<height>16777215</height>
</size>
</property>
</widget>
</item>
<item row="1" column="4">
<spacer name="horizontalSpacer_5">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="0" column="0">
<widget class="QCheckBox" name="gridStuds">
<property name="text">
<string>Draw studs</string>
</property>
</widget>
</item>
<item row="1" column="2">
<widget class="QLabel" name="label">
<property name="text">
<string>studs</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QCheckBox" name="gridLines">
<property name="text">
<string>Draw lines every</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QToolButton" name="gridStudColor">
<property name="text">
<string/>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item row="1" column="0">
<widget class="QCheckBox" name="edgeLines">
<property name="text">
<string>Edge lines</string>
</property>
</widget>
</item>
<item row="8" column="0">
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
@ -253,93 +389,6 @@
</property>
</spacer>
</item>
<item row="5" column="0">
<widget class="QCheckBox" name="fastRendering">
<property name="text">
<string>Fast rendering</string>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QCheckBox" name="enableLighting">
<property name="text">
<string>Enable lighting</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLineEdit" name="lineWidth">
<property name="maximumSize">
<size>
<width>75</width>
<height>16777215</height>
</size>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QComboBox" name="antiAliasingSamples">
<item>
<property name="text">
<string>2x</string>
</property>
</item>
<item>
<property name="text">
<string>4x</string>
</property>
</item>
<item>
<property name="text">
<string>8x</string>
</property>
</item>
</widget>
</item>
<item row="3" column="0">
<widget class="QCheckBox" name="axisIcon">
<property name="text">
<string>Axis icon</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QLineEdit" name="gridUnits">
<property name="maximumSize">
<size>
<width>75</width>
<height>16777215</height>
</size>
</property>
</widget>
</item>
<item row="2" column="2">
<widget class="QLabel" name="label">
<property name="text">
<string>units</string>
</property>
</widget>
</item>
<item row="1" column="2">
<widget class="QLabel" name="label_2">
<property name="text">
<string>width</string>
</property>
</widget>
</item>
<item row="0" column="3">
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<widget class="QWidget" name="tabCategories">
@ -689,11 +738,14 @@
<tabstop>antiAliasingSamples</tabstop>
<tabstop>edgeLines</tabstop>
<tabstop>lineWidth</tabstop>
<tabstop>baseGrid</tabstop>
<tabstop>gridUnits</tabstop>
<tabstop>axisIcon</tabstop>
<tabstop>enableLighting</tabstop>
<tabstop>fastRendering</tabstop>
<tabstop>gridStuds</tabstop>
<tabstop>gridStudColor</tabstop>
<tabstop>gridLines</tabstop>
<tabstop>gridLineSpacing</tabstop>
<tabstop>gridLineColor</tabstop>
<tabstop>categoriesTree</tabstop>
<tabstop>partsTree</tabstop>
<tabstop>importCategories</tabstop>