2011-09-07 23:06:51 +02:00
|
|
|
// Everything that is a part of a LeoCAD project goes here.
|
|
|
|
//
|
|
|
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <float.h>
|
|
|
|
#include <math.h>
|
|
|
|
#include <locale.h>
|
|
|
|
#include "opengl.h"
|
|
|
|
#include "vector.h"
|
|
|
|
#include "matrix.h"
|
|
|
|
#include "pieceinf.h"
|
|
|
|
#include "texture.h"
|
|
|
|
#include "piece.h"
|
|
|
|
#include "camera.h"
|
|
|
|
#include "light.h"
|
|
|
|
#include "group.h"
|
|
|
|
#include "terrain.h"
|
|
|
|
#include "project.h"
|
|
|
|
#include "image.h"
|
|
|
|
#include "system.h"
|
|
|
|
#include "globals.h"
|
|
|
|
#include "minifig.h"
|
|
|
|
#include "config.h"
|
|
|
|
#include "message.h"
|
|
|
|
#include "curve.h"
|
|
|
|
#include "mainwnd.h"
|
|
|
|
#include "view.h"
|
|
|
|
#include "library.h"
|
|
|
|
#include "texfont.h"
|
|
|
|
#include "algebra.h"
|
|
|
|
#include "debug.h"
|
|
|
|
#include "lc_application.h"
|
|
|
|
|
|
|
|
// FIXME: temporary function, replace the code !!!
|
|
|
|
void SystemUpdateFocus (void* p)
|
|
|
|
{
|
|
|
|
messenger->Dispatch (LC_MSG_FOCUS_CHANGED, p);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void ProjectListener(int Message, void* Data, void* User)
|
|
|
|
{
|
|
|
|
((Project*)User)->HandleMessage(Message, Data);
|
|
|
|
}
|
|
|
|
|
|
|
|
typedef struct
|
|
|
|
{
|
|
|
|
unsigned char n;
|
|
|
|
float dim [4][4];
|
|
|
|
} LC_VIEWPORT;
|
|
|
|
|
|
|
|
static LC_VIEWPORT viewports[14] = {
|
|
|
|
{ 1, {{ 0.0f, 0.0f, 1.0f, 1.0f }, { 0.0f, 0.0f, 0.0f, 0.0f },
|
|
|
|
{ 0.0f, 0.0f, 0.0f, 0.0f }, { 0.0f, 0.0f, 0.0f, 0.0f } }}, // 1
|
|
|
|
{ 2, {{ 0.0f, 0.0f, 0.5f, 1.0f }, { 0.5f, 0.0f, 0.5f, 1.0f },
|
|
|
|
{ 0.0f, 0.0f, 0.0f, 0.0f }, { 0.0f, 0.0f, 0.0f, 0.0f } }}, // 2V
|
|
|
|
{ 2, {{ 0.0f, 0.0f, 1.0f, 0.5f }, { 0.0f, 0.5f, 1.0f, 0.5f },
|
|
|
|
{ 0.0f, 0.0f, 0.0f, 0.0f }, { 0.0f, 0.0f, 0.0f, 0.0f } }}, // 2H
|
|
|
|
{ 2, {{ 0.0f, 0.0f, 1.0f, 0.7f }, { 0.0f, 0.7f, 1.0f, 0.3f },
|
|
|
|
{ 0.0f, 0.0f, 0.0f, 0.0f }, { 0.0f, 0.0f, 0.0f, 0.0f } }}, // 2HT
|
|
|
|
{ 2, {{ 0.0f, 0.0f, 1.0f, 0.3f }, { 0.0f, 0.3f, 1.0f, 0.7f },
|
|
|
|
{ 0.0f, 0.0f, 0.0f, 0.0f }, { 0.0f, 0.0f, 0.0f, 0.0f } }}, // 2HB
|
|
|
|
{ 3, {{ 0.0f, 0.0f, 0.5f, 0.5f }, { 0.0f, 0.5f, 0.5f, 0.5f },
|
|
|
|
{ 0.5f, 0.0f, 0.5f, 1.0f }, { 0.0f, 0.0f, 0.0f, 0.0f } }}, // 3VL
|
|
|
|
{ 3, {{ 0.0f, 0.0f, 0.5f, 1.0f }, { 0.5f, 0.0f, 0.5f, 0.5f },
|
|
|
|
{ 0.5f, 0.5f, 0.5f, 0.5f }, { 0.0f, 0.0f, 0.0f, 0.0f } }}, // 3VR
|
|
|
|
{ 3, {{ 0.0f, 0.0f, 1.0f, 0.5f }, { 0.0f, 0.5f, 0.5f, 0.5f },
|
|
|
|
{ 0.5f, 0.5f, 0.5f, 0.5f }, { 0.0f, 0.0f, 0.0f, 0.0f } }}, // 3HB
|
|
|
|
{ 3, {{ 0.0f, 0.0f, 0.5f, 0.5f }, { 0.5f, 0.0f, 0.5f, 0.5f },
|
|
|
|
{ 0.0f, 0.5f, 1.0f, 0.5f }, { 0.0f, 0.0f, 0.0f, 0.0f } }}, // 3HT
|
|
|
|
{ 4, {{ 0.0f, 0.0f, 0.3f, 0.3f }, { 0.0f, 0.3f, 0.3f, 0.4f },
|
|
|
|
{ 0.0f, 0.7f, 0.3f, 0.3f }, { 0.3f, 0.0f, 0.7f, 1.0f } }}, // 4VL
|
|
|
|
{ 4, {{ 0.0f, 0.0f, 0.7f, 1.0f }, { 0.7f, 0.0f, 0.3f, 0.3f },
|
|
|
|
{ 0.7f, 0.3f, 0.3f, 0.4f }, { 0.7f, 0.7f, 0.3f, 0.3f } }}, // 4VR
|
|
|
|
{ 4, {{ 0.0f, 0.0f, 1.0f, 0.7f }, { 0.0f, 0.7f, 0.3f, 0.3f },
|
|
|
|
{ 0.3f, 0.7f, 0.4f, 0.3f }, { 0.7f, 0.7f, 0.3f, 0.3f } }}, // 4HT
|
|
|
|
{ 4, {{ 0.0f, 0.0f, 0.3f, 0.3f }, { 0.3f, 0.0f, 0.4f, 0.3f },
|
|
|
|
{ 0.7f, 0.0f, 0.3f, 0.3f }, { 0.0f, 0.3f, 1.0f, 0.7f } }}, // 4HB
|
|
|
|
{ 4, {{ 0.0f, 0.0f, 0.5f, 0.5f }, { 0.5f, 0.0f, 0.5f, 0.5f },
|
|
|
|
{ 0.0f, 0.5f, 0.5f, 0.5f }, { 0.5f, 0.5f, 0.5f, 0.5f } }}};// 4
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
// Project construction/destruction
|
|
|
|
|
|
|
|
Project::Project()
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
2011-09-17 01:59:55 +02:00
|
|
|
m_ActiveView = NULL;
|
2011-09-07 23:06:51 +02:00
|
|
|
m_bModified = false;
|
|
|
|
m_bTrackCancel = false;
|
|
|
|
m_nTracking = LC_TRACK_NONE;
|
|
|
|
m_pPieces = NULL;
|
|
|
|
m_pCameras = NULL;
|
|
|
|
m_pLights = NULL;
|
|
|
|
m_pGroups = NULL;
|
|
|
|
m_pUndoList = NULL;
|
|
|
|
m_pRedoList = NULL;
|
|
|
|
m_nGridList = 0;
|
2011-09-17 01:59:55 +02:00
|
|
|
m_pTrackFile = NULL;
|
2011-09-07 23:06:51 +02:00
|
|
|
m_nCurClipboard = 0;
|
|
|
|
m_nCurAction = 0;
|
|
|
|
m_pTerrain = new Terrain();
|
|
|
|
m_pBackground = new Texture();
|
|
|
|
m_nAutosave = Sys_ProfileLoadInt ("Settings", "Autosave", 10);
|
|
|
|
m_nMouse = Sys_ProfileLoadInt ("Default", "Mouse", 11);
|
|
|
|
strcpy(m_strModelsPath, Sys_ProfileLoadString ("Default", "Projects", ""));
|
|
|
|
|
|
|
|
if (messenger == NULL)
|
|
|
|
messenger = new Messenger ();
|
|
|
|
messenger->AddRef();
|
|
|
|
messenger->Listen(&ProjectListener, this);
|
|
|
|
|
|
|
|
for (i = 0; i < LC_CONNECTIONS; i++)
|
|
|
|
{
|
|
|
|
m_pConnections[i].entries = NULL;
|
|
|
|
m_pConnections[i].numentries = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < 10; i++)
|
|
|
|
m_pClipboard[i] = NULL;
|
|
|
|
|
|
|
|
m_pScreenFont = new TexFont();
|
|
|
|
}
|
|
|
|
|
|
|
|
Project::~Project()
|
|
|
|
{
|
|
|
|
DeleteContents(false);
|
|
|
|
SystemFinish();
|
|
|
|
|
|
|
|
if (m_pTrackFile)
|
|
|
|
{
|
|
|
|
delete m_pTrackFile;
|
|
|
|
m_pTrackFile = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (int i = 0; i < 10; i++)
|
|
|
|
if (m_pClipboard[i] != NULL)
|
|
|
|
delete m_pClipboard[i];
|
|
|
|
|
|
|
|
messenger->DecRef ();
|
|
|
|
|
|
|
|
delete m_pTerrain;
|
|
|
|
delete m_pBackground;
|
|
|
|
delete m_pScreenFont;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
// Project attributes, general services
|
|
|
|
|
|
|
|
void Project::UpdateInterface()
|
|
|
|
{
|
|
|
|
// Update all user interface elements.
|
|
|
|
SystemUpdateUndoRedo(m_pUndoList->pNext ? m_pUndoList->strText : NULL, m_pRedoList ? m_pRedoList->strText : NULL);
|
|
|
|
SystemUpdatePaste(m_pClipboard[m_nCurClipboard] != NULL);
|
|
|
|
SystemUpdatePlay(true, false);
|
|
|
|
SystemUpdateCategories(false);
|
|
|
|
SetTitle(m_strTitle);
|
|
|
|
|
|
|
|
SystemUpdateFocus(NULL);
|
|
|
|
SetAction(m_nCurAction);
|
|
|
|
SystemUpdateViewport(m_nViewportMode, 0);
|
|
|
|
SystemUpdateColorList(m_nCurColor);
|
|
|
|
SystemUpdateAnimation(m_bAnimation, m_bAddKeys);
|
2011-09-20 01:03:28 +02:00
|
|
|
SystemUpdateRenderingMode((m_nDetail & LC_DET_FAST) != 0);
|
2011-09-07 23:06:51 +02:00
|
|
|
SystemUpdateSnap(m_nSnap);
|
|
|
|
SystemUpdateSnap(m_nMoveSnap, m_nAngleSnap);
|
|
|
|
SystemUpdateCameraMenu(m_pCameras);
|
|
|
|
SystemUpdateCurrentCamera(NULL, m_pViewCameras[m_nActiveViewport], m_pCameras);
|
|
|
|
UpdateSelection();
|
|
|
|
if (m_bAnimation)
|
|
|
|
SystemUpdateTime(m_bAnimation, m_nCurFrame, m_nTotalFrames);
|
|
|
|
else
|
|
|
|
SystemUpdateTime(m_bAnimation, m_nCurStep, 255);
|
|
|
|
|
|
|
|
for (int i = 0; i < m_ViewList.GetSize(); i++)
|
|
|
|
{
|
|
|
|
m_ViewList[i]->MakeCurrent();
|
|
|
|
RenderInitialize();
|
|
|
|
}
|
|
|
|
|
|
|
|
UpdateSelection();
|
|
|
|
}
|
|
|
|
|
|
|
|
void Project::SetTitle(const char* lpszTitle)
|
|
|
|
{
|
|
|
|
if (lpszTitle != m_strTitle)
|
|
|
|
strcpy(m_strTitle, lpszTitle);
|
|
|
|
|
|
|
|
char title[LC_MAXPATH], *ptr, ext[4];
|
|
|
|
strcpy(title, m_strTitle);
|
|
|
|
|
|
|
|
ptr = strrchr(title, '.');
|
|
|
|
if (ptr != NULL)
|
|
|
|
{
|
|
|
|
strncpy(ext, ptr+1, 3);
|
|
|
|
ext[3] = 0;
|
|
|
|
strlwr(ext);
|
|
|
|
|
|
|
|
if (strcmp(ext, "lcd") == 0)
|
|
|
|
*ptr = 0;
|
|
|
|
if (strcmp(ext, "dat") == 0)
|
|
|
|
*ptr = 0;
|
|
|
|
if (strcmp(ext, "ldr") == 0)
|
|
|
|
*ptr = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
strcat(title, " - LeoCAD");
|
|
|
|
|
|
|
|
SystemSetWindowCaption(title);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Project::DeleteContents(bool bUndo)
|
|
|
|
{
|
|
|
|
Piece* pPiece;
|
|
|
|
Camera* pCamera;
|
|
|
|
Light* pLight;
|
|
|
|
Group* pGroup;
|
|
|
|
|
|
|
|
memset(m_strAuthor, 0, sizeof(m_strAuthor));
|
|
|
|
memset(m_strDescription, 0, sizeof(m_strDescription));
|
|
|
|
memset(m_strComments, 0, sizeof(m_strComments));
|
|
|
|
|
|
|
|
if (!bUndo)
|
|
|
|
{
|
|
|
|
LC_UNDOINFO* pUndo;
|
|
|
|
|
|
|
|
while (m_pUndoList)
|
|
|
|
{
|
|
|
|
pUndo = m_pUndoList;
|
|
|
|
m_pUndoList = m_pUndoList->pNext;
|
|
|
|
delete pUndo;
|
|
|
|
}
|
|
|
|
|
|
|
|
while (m_pRedoList)
|
|
|
|
{
|
|
|
|
pUndo = m_pRedoList;
|
|
|
|
m_pRedoList = m_pRedoList->pNext;
|
|
|
|
delete pUndo;
|
|
|
|
}
|
|
|
|
|
|
|
|
m_pRedoList = NULL;
|
|
|
|
m_pUndoList = NULL;
|
|
|
|
|
|
|
|
m_pBackground->Unload();
|
2011-09-20 01:03:28 +02:00
|
|
|
m_pTerrain->LoadDefaults(true);
|
2011-09-07 23:06:51 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
while (m_pPieces)
|
|
|
|
{
|
|
|
|
pPiece = m_pPieces;
|
|
|
|
m_pPieces = m_pPieces->m_pNext;
|
|
|
|
delete pPiece;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (int i = 0; i < LC_CONNECTIONS; i++)
|
|
|
|
{
|
|
|
|
for (int j = 0; j < m_pConnections[i].numentries; j++)
|
|
|
|
delete (m_pConnections[i].entries[j].cons);
|
|
|
|
|
|
|
|
delete m_pConnections[i].entries;
|
|
|
|
m_pConnections[i].entries = NULL;
|
|
|
|
m_pConnections[i].numentries = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
while (m_pCameras)
|
|
|
|
{
|
|
|
|
pCamera = m_pCameras;
|
|
|
|
m_pCameras = m_pCameras->m_pNext;
|
|
|
|
delete pCamera;
|
|
|
|
}
|
|
|
|
|
|
|
|
while (m_pLights)
|
|
|
|
{
|
|
|
|
pLight = m_pLights;
|
|
|
|
m_pLights = m_pLights->m_pNext;
|
|
|
|
delete pLight;
|
|
|
|
}
|
|
|
|
|
|
|
|
while (m_pGroups)
|
|
|
|
{
|
|
|
|
pGroup = m_pGroups;
|
|
|
|
m_pGroups = m_pGroups->m_pNext;
|
|
|
|
delete pGroup;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
if (!m_strTempFile.IsEmpty())
|
|
|
|
{
|
|
|
|
DeleteFile (m_strTempFile);
|
|
|
|
m_strTempFile.Empty();
|
|
|
|
}
|
|
|
|
*/
|
|
|
|
}
|
|
|
|
|
|
|
|
// Only call after DeleteContents()
|
|
|
|
void Project::LoadDefaults(bool cameras)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
unsigned long rgb;
|
|
|
|
|
|
|
|
// Default values
|
|
|
|
m_nActiveViewport = 0;
|
|
|
|
SystemUpdateViewport(0, m_nViewportMode);
|
|
|
|
m_nViewportMode = 0;
|
|
|
|
SetAction(0);
|
|
|
|
m_nCurColor = 0;
|
|
|
|
SystemUpdateColorList(m_nCurColor);
|
|
|
|
m_bAnimation = false;
|
|
|
|
m_bAddKeys = false;
|
|
|
|
SystemUpdateAnimation(m_bAnimation, m_bAddKeys);
|
|
|
|
m_bUndoOriginal = true;
|
|
|
|
SystemUpdateUndoRedo(NULL, NULL);
|
|
|
|
m_nDetail = Sys_ProfileLoadInt ("Default", "Detail", LC_DET_BRICKEDGES);
|
2011-09-20 01:03:28 +02:00
|
|
|
SystemUpdateRenderingMode((m_nDetail & LC_DET_FAST) != 0);
|
2011-09-07 23:06:51 +02:00
|
|
|
m_nAngleSnap = (unsigned short)Sys_ProfileLoadInt ("Default", "Angle", 30);
|
|
|
|
m_nSnap = Sys_ProfileLoadInt ("Default", "Snap", LC_DRAW_SNAP_A | LC_DRAW_SNAP_X | LC_DRAW_SNAP_Y | LC_DRAW_SNAP_Z | LC_DRAW_MOVE);
|
|
|
|
SystemUpdateSnap(m_nSnap);
|
|
|
|
m_nMoveSnap = 0x0304;
|
|
|
|
SystemUpdateSnap(m_nMoveSnap, m_nAngleSnap);
|
|
|
|
m_fLineWidth = (float)Sys_ProfileLoadInt ("Default", "Line", 100)/100;
|
|
|
|
m_fFogDensity = (float)Sys_ProfileLoadInt ("Default", "Density", 10)/100;
|
|
|
|
rgb = Sys_ProfileLoadInt ("Default", "Fog", 0xFFFFFF);
|
|
|
|
m_fFogColor[0] = (float)((unsigned char) (rgb))/255;
|
|
|
|
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)Sys_ProfileLoadInt ("Default", "Grid", 20);
|
|
|
|
rgb = Sys_ProfileLoadInt ("Default", "Ambient", 0x4B4B4B);
|
|
|
|
m_fAmbient[0] = (float)((unsigned char) (rgb))/255;
|
|
|
|
m_fAmbient[1] = (float)((unsigned char) (((unsigned short) (rgb)) >> 8))/255;
|
|
|
|
m_fAmbient[2] = (float)((unsigned char) ((rgb) >> 16))/255;
|
|
|
|
m_fAmbient[3] = 1.0f;
|
|
|
|
rgb = Sys_ProfileLoadInt ("Default", "Background", 0xFFFFFF);
|
|
|
|
m_fBackground[0] = (float)((unsigned char) (rgb))/255;
|
|
|
|
m_fBackground[1] = (float)((unsigned char) (((unsigned short) (rgb)) >> 8))/255;
|
|
|
|
m_fBackground[2] = (float)((unsigned char) ((rgb) >> 16))/255;
|
|
|
|
m_fBackground[3] = 1.0f;
|
|
|
|
rgb = Sys_ProfileLoadInt ("Default", "Gradient1", 0xBF0000);
|
|
|
|
m_fGradient1[0] = (float)((unsigned char) (rgb))/255;
|
|
|
|
m_fGradient1[1] = (float)((unsigned char) (((unsigned short) (rgb)) >> 8))/255;
|
|
|
|
m_fGradient1[2] = (float)((unsigned char) ((rgb) >> 16))/255;
|
|
|
|
rgb = Sys_ProfileLoadInt ("Default", "Gradient2", 0xFFFFFF);
|
|
|
|
m_fGradient2[0] = (float)((unsigned char) (rgb))/255;
|
|
|
|
m_fGradient2[1] = (float)((unsigned char) (((unsigned short) (rgb)) >> 8))/255;
|
|
|
|
m_fGradient2[2] = (float)((unsigned char) ((rgb) >> 16))/255;
|
|
|
|
m_nFPS = Sys_ProfileLoadInt ("Default", "FPS", 24);
|
|
|
|
m_nCurStep = 1;
|
|
|
|
m_nCurFrame = 1;
|
|
|
|
m_nTotalFrames = 100;
|
|
|
|
SystemUpdateTime(false, 1, 255);
|
|
|
|
m_nScene = Sys_ProfileLoadInt ("Default", "Scene", 0);
|
|
|
|
m_nSaveTimer = 0;
|
|
|
|
strcpy(m_strHeader, Sys_ProfileLoadString ("Default", "Header", ""));
|
|
|
|
strcpy(m_strFooter, Sys_ProfileLoadString ("Default", "Footer", "Page &P"));
|
|
|
|
strcpy(m_strBackground, Sys_ProfileLoadString ("Default", "BMP", ""));
|
2011-09-20 01:03:28 +02:00
|
|
|
m_pTerrain->LoadDefaults(true);
|
2011-09-07 23:06:51 +02:00
|
|
|
m_OverlayActive = false;
|
|
|
|
|
|
|
|
for (i = 0; i < m_ViewList.GetSize (); i++)
|
|
|
|
{
|
|
|
|
m_ViewList[i]->MakeCurrent ();
|
|
|
|
RenderInitialize();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (cameras)
|
|
|
|
{
|
|
|
|
Camera* pCam;
|
|
|
|
for (pCam = NULL, i = 0; i < 7; i++)
|
|
|
|
{
|
|
|
|
pCam = new Camera(i, pCam);
|
|
|
|
if (m_pCameras == NULL)
|
|
|
|
m_pCameras = pCam;
|
|
|
|
|
|
|
|
switch (i)
|
|
|
|
{
|
|
|
|
case LC_CAMERA_MAIN: m_pViewCameras[0] = pCam; break;
|
|
|
|
case LC_CAMERA_FRONT: m_pViewCameras[1] = pCam; break;
|
|
|
|
case LC_CAMERA_TOP: m_pViewCameras[2] = pCam; break;
|
|
|
|
case LC_CAMERA_RIGHT: m_pViewCameras[3] = pCam; break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
SystemUpdateCameraMenu(m_pCameras);
|
|
|
|
SystemUpdateCurrentCamera(NULL, m_pViewCameras[0], m_pCameras);
|
|
|
|
}
|
|
|
|
SystemPieceComboAdd(NULL);
|
|
|
|
UpdateSelection();
|
|
|
|
}
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
// Standard file menu commands
|
|
|
|
|
|
|
|
// Read a .lcd file
|
|
|
|
bool Project::FileLoad(File* file, bool bUndo, bool bMerge)
|
|
|
|
{
|
|
|
|
int i, count;
|
|
|
|
char id[32];
|
|
|
|
unsigned long rgb;
|
|
|
|
float fv = 0.4f;
|
|
|
|
unsigned char ch, action = m_nCurAction;
|
|
|
|
unsigned short sh;
|
|
|
|
|
|
|
|
file->Seek(0, SEEK_SET);
|
|
|
|
file->Read(id, 32);
|
|
|
|
sscanf(&id[7], "%f", &fv);
|
|
|
|
|
|
|
|
// Fix the ugly floating point reading on computers with different decimal points.
|
|
|
|
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->ReadFloat (&fv, 1);
|
|
|
|
|
|
|
|
file->ReadLong (&rgb, 1);
|
|
|
|
if (!bMerge)
|
|
|
|
{
|
|
|
|
m_fBackground[0] = (float)((unsigned char) (rgb))/255;
|
|
|
|
m_fBackground[1] = (float)((unsigned char) (((unsigned short) (rgb)) >> 8))/255;
|
|
|
|
m_fBackground[2] = (float)((unsigned char) ((rgb) >> 16))/255;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (fv < 0.6f) // old view
|
|
|
|
{
|
|
|
|
Camera* pCam;
|
|
|
|
for (pCam = NULL, i = 0; i < 7; i++)
|
|
|
|
{
|
|
|
|
pCam = new Camera(i, pCam);
|
|
|
|
if (m_pCameras == NULL)
|
|
|
|
m_pCameras = pCam;
|
|
|
|
|
|
|
|
switch (i)
|
|
|
|
{
|
|
|
|
case LC_CAMERA_MAIN: m_pViewCameras[0] = pCam; break;
|
|
|
|
case LC_CAMERA_FRONT: m_pViewCameras[1] = pCam; break;
|
|
|
|
case LC_CAMERA_TOP: m_pViewCameras[2] = pCam; break;
|
|
|
|
case LC_CAMERA_RIGHT: m_pViewCameras[3] = pCam; break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
double eye[3], target[3];
|
|
|
|
file->ReadDouble (&eye, 3);
|
|
|
|
file->ReadDouble (&target, 3);
|
|
|
|
float tmp[3] = { (float)eye[0], (float)eye[1], (float)eye[2] };
|
|
|
|
pCam->ChangeKey(1, false, false, tmp, LC_CK_EYE);
|
|
|
|
pCam->ChangeKey(1, true, false, tmp, LC_CK_EYE);
|
|
|
|
tmp[0] = (float)target[0]; tmp[1] = (float)target[1]; tmp[2] = (float)target[2];
|
|
|
|
pCam->ChangeKey(1, false, false, tmp, LC_CK_TARGET);
|
|
|
|
pCam->ChangeKey(1, true, false, tmp, LC_CK_TARGET);
|
|
|
|
|
|
|
|
// Create up vector
|
|
|
|
Vector upvec(0,0,1), frontvec((float)(eye[0]-target[0]), (float)(eye[1]-target[1]), (float)(eye[2]-target[2])), sidevec;
|
|
|
|
frontvec.Normalize();
|
|
|
|
if (frontvec == upvec)
|
|
|
|
sidevec = Vector(1,0,0);
|
|
|
|
else
|
|
|
|
sidevec.Cross(frontvec, upvec);
|
|
|
|
upvec.Cross(sidevec, frontvec);
|
|
|
|
upvec.Normalize();
|
|
|
|
upvec.ToFloat(tmp);
|
|
|
|
pCam->ChangeKey(1, false, false, tmp, LC_CK_UP);
|
|
|
|
pCam->ChangeKey(1, true, false, tmp, LC_CK_UP);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (bMerge)
|
|
|
|
file->Seek(32, SEEK_CUR);
|
|
|
|
else
|
|
|
|
{
|
|
|
|
file->ReadLong (&i, 1); m_nAngleSnap = i;
|
|
|
|
file->ReadLong (&m_nSnap, 1);
|
|
|
|
file->ReadFloat (&m_fLineWidth, 1);
|
|
|
|
file->ReadLong (&m_nDetail, 1);
|
|
|
|
file->ReadLong (&i, 1); //m_nCurGroup = i;
|
|
|
|
file->ReadLong (&i, 1); m_nCurColor = i;
|
|
|
|
file->ReadLong (&i, 1); action = i;
|
|
|
|
file->ReadLong (&i, 1); m_nCurStep = i;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (fv > 0.8f)
|
|
|
|
file->ReadLong (&m_nScene, 1);
|
|
|
|
|
|
|
|
file->ReadLong (&count, 1);
|
|
|
|
SystemStartProgressBar(0, count, 1, "Loading project...");
|
|
|
|
|
|
|
|
while (count--)
|
|
|
|
{
|
|
|
|
if (fv > 0.4f)
|
|
|
|
{
|
|
|
|
char name[LC_PIECE_NAME_LEN];
|
|
|
|
Piece* pPiece = new Piece(NULL);
|
|
|
|
pPiece->FileLoad(*file, name);
|
|
|
|
PieceInfo* pInfo = lcGetPiecesLibrary()->FindPieceInfo(name);
|
|
|
|
if (pInfo)
|
|
|
|
{
|
|
|
|
pPiece->SetPieceInfo(pInfo);
|
|
|
|
|
|
|
|
if (bMerge)
|
|
|
|
for (Piece* p = m_pPieces; p; p = p->m_pNext)
|
|
|
|
if (strcmp(p->GetName(), pPiece->GetName()) == 0)
|
|
|
|
{
|
|
|
|
pPiece->CreateName(m_pPieces);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (strlen(pPiece->GetName()) == 0)
|
|
|
|
pPiece->CreateName(m_pPieces);
|
|
|
|
|
|
|
|
AddPiece(pPiece);
|
|
|
|
if (!bUndo)
|
|
|
|
SystemPieceComboAdd(pInfo->m_strDescription);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
delete pPiece;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
char name[LC_PIECE_NAME_LEN];
|
|
|
|
float pos[3], rot[3], param[4];
|
|
|
|
unsigned char color, step, group;
|
|
|
|
|
|
|
|
file->ReadFloat (pos, 3);
|
|
|
|
file->ReadFloat (rot, 3);
|
|
|
|
file->ReadByte (&color, 1);
|
|
|
|
file->Read(name, sizeof(name));
|
|
|
|
file->ReadByte (&step, 1);
|
|
|
|
file->ReadByte (&group, 1);
|
|
|
|
|
|
|
|
const unsigned char conv[20] = { 0,2,4,9,7,6,22,8,10,11,14,16,18,9,21,20,22,8,10,11 };
|
|
|
|
color = conv[color];
|
|
|
|
|
|
|
|
PieceInfo* pInfo = lcGetPiecesLibrary()->FindPieceInfo(name);
|
|
|
|
if (pInfo != NULL)
|
|
|
|
{
|
|
|
|
Piece* pPiece = new Piece(pInfo);
|
|
|
|
Matrix mat;
|
|
|
|
|
|
|
|
pPiece->Initialize(pos[0], pos[1], pos[2], step, 1, color);
|
|
|
|
pPiece->CreateName(m_pPieces);
|
|
|
|
AddPiece(pPiece);
|
|
|
|
mat.CreateOld(0,0,0, rot[0],rot[1],rot[2]);
|
|
|
|
mat.ToAxisAngle(param);
|
|
|
|
pPiece->ChangeKey(1, false, false, param, LC_PK_ROTATION);
|
|
|
|
pPiece->ChangeKey(1, true, false, param, LC_PK_ROTATION);
|
|
|
|
// pPiece->SetGroup((Group*)group);
|
|
|
|
SystemPieceComboAdd(pInfo->m_strDescription);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
SytemStepProgressBar();
|
|
|
|
}
|
|
|
|
SytemEndProgressBar();
|
|
|
|
|
|
|
|
if (!bMerge)
|
|
|
|
{
|
|
|
|
if (fv >= 0.4f)
|
|
|
|
{
|
|
|
|
file->Read(&ch, 1);
|
|
|
|
if (ch == 0xFF) file->ReadShort (&sh, 1); else sh = ch;
|
|
|
|
if (sh > 100)
|
|
|
|
file->Seek(sh, SEEK_CUR);
|
|
|
|
else
|
|
|
|
file->Read(m_strAuthor, sh);
|
|
|
|
|
|
|
|
file->Read(&ch, 1);
|
|
|
|
if (ch == 0xFF) file->ReadShort (&sh, 1); else sh = ch;
|
|
|
|
if (sh > 100)
|
|
|
|
file->Seek(sh, SEEK_CUR);
|
|
|
|
else
|
|
|
|
file->Read(m_strDescription, sh);
|
|
|
|
|
|
|
|
file->Read(&ch, 1);
|
|
|
|
if (ch == 0xFF && fv < 1.3f) file->ReadShort (&sh, 1); else sh = ch;
|
|
|
|
if (sh > 255)
|
|
|
|
file->Seek(sh, SEEK_CUR);
|
|
|
|
else
|
|
|
|
file->Read(m_strComments, sh);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (fv >= 0.4f)
|
|
|
|
{
|
|
|
|
file->Read (&ch, 1);
|
|
|
|
if (ch == 0xFF) file->ReadShort (&sh, 1); else sh = ch;
|
|
|
|
file->Seek (sh, SEEK_CUR);
|
|
|
|
|
|
|
|
file->Read (&ch, 1);
|
|
|
|
if (ch == 0xFF) file->ReadShort (&sh, 1); else sh = ch;
|
|
|
|
file->Seek (sh, SEEK_CUR);
|
|
|
|
|
|
|
|
file->Read (&ch, 1);
|
|
|
|
if (ch == 0xFF && fv < 1.3f) file->ReadShort (&sh, 1); else sh = ch;
|
|
|
|
file->Seek (sh, SEEK_CUR);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (fv >= 0.5f)
|
|
|
|
{
|
|
|
|
file->ReadLong (&count, 1);
|
|
|
|
|
|
|
|
Group* pGroup;
|
|
|
|
Group* pLastGroup = NULL;
|
|
|
|
for (pGroup = m_pGroups; pGroup; pGroup = pGroup->m_pNext)
|
|
|
|
pLastGroup = pGroup;
|
|
|
|
|
|
|
|
pGroup = pLastGroup;
|
|
|
|
for (i = 0; i < count; i++)
|
|
|
|
{
|
|
|
|
if (pGroup)
|
|
|
|
{
|
|
|
|
pGroup->m_pNext = new Group();
|
|
|
|
pGroup = pGroup->m_pNext;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
m_pGroups = pGroup = new Group();
|
|
|
|
}
|
|
|
|
pLastGroup = pLastGroup ? pLastGroup->m_pNext : m_pGroups;
|
|
|
|
|
|
|
|
for (pGroup = pLastGroup; pGroup; pGroup = pGroup->m_pNext)
|
|
|
|
{
|
|
|
|
if (fv < 1.0f)
|
|
|
|
{
|
|
|
|
file->Read(pGroup->m_strName, 65);
|
|
|
|
file->Read(&ch, 1);
|
|
|
|
pGroup->m_fCenter[0] = 0;
|
|
|
|
pGroup->m_fCenter[1] = 0;
|
|
|
|
pGroup->m_fCenter[2] = 0;
|
|
|
|
pGroup->m_pGroup = (Group*)-1;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
pGroup->FileLoad(file);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (pGroup = pLastGroup; pGroup; pGroup = pGroup->m_pNext)
|
|
|
|
{
|
|
|
|
i = LC_POINTER_TO_INT(pGroup->m_pGroup);
|
|
|
|
pGroup->m_pGroup = NULL;
|
|
|
|
|
|
|
|
if (i > 0xFFFF || i == -1)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
for (Group* g2 = pLastGroup; g2; g2 = g2->m_pNext)
|
|
|
|
{
|
|
|
|
if (i == 0)
|
|
|
|
{
|
|
|
|
pGroup->m_pGroup = g2;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
i--;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Piece* pPiece;
|
|
|
|
for (pPiece = m_pPieces; pPiece; pPiece = pPiece->m_pNext)
|
|
|
|
{
|
|
|
|
i = LC_POINTER_TO_INT(pPiece->GetGroup());
|
|
|
|
pPiece->SetGroup(NULL);
|
|
|
|
|
|
|
|
if (i > 0xFFFF || i == -1)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
for (pGroup = pLastGroup; pGroup; pGroup = pGroup->m_pNext)
|
|
|
|
{
|
|
|
|
if (i == 0)
|
|
|
|
{
|
|
|
|
pPiece->SetGroup(pGroup);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
i--;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
RemoveEmptyGroups();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!bMerge)
|
|
|
|
{
|
|
|
|
if (fv >= 0.6f)
|
|
|
|
{
|
|
|
|
if (fv < 1.0f)
|
|
|
|
{
|
|
|
|
file->ReadLong (&i, 1);
|
|
|
|
m_nViewportMode = i;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
file->ReadByte (&m_nViewportMode, 1);
|
|
|
|
file->ReadByte (&m_nActiveViewport, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
file->ReadLong (&count, 1);
|
|
|
|
Camera* pCam = NULL;
|
|
|
|
for (i = 0; i < count; i++)
|
|
|
|
{
|
|
|
|
pCam = new Camera(i, pCam);
|
|
|
|
if (m_pCameras == NULL)
|
|
|
|
m_pCameras = pCam;
|
|
|
|
|
|
|
|
if (i < 4 && fv == 0.6f)
|
|
|
|
m_pViewCameras[i] = pCam;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (count < 7)
|
|
|
|
{
|
|
|
|
pCam = new Camera(0, NULL);
|
|
|
|
for (i = 0; i < count; i++)
|
|
|
|
pCam->FileLoad(*file);
|
|
|
|
delete pCam;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
for (pCam = m_pCameras; pCam; pCam = pCam->m_pNext)
|
|
|
|
pCam->FileLoad(*file);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (fv >= 0.7f)
|
|
|
|
{
|
|
|
|
for (count = 0; count < 4; count++)
|
|
|
|
{
|
|
|
|
file->ReadLong (&i, 1);
|
|
|
|
|
|
|
|
Camera* pCam = m_pCameras;
|
|
|
|
while (i--)
|
|
|
|
pCam = pCam->m_pNext;
|
|
|
|
m_pViewCameras[count] = pCam;
|
|
|
|
}
|
|
|
|
|
|
|
|
file->ReadLong (&rgb, 1);
|
|
|
|
m_fFogColor[0] = (float)((unsigned char) (rgb))/255;
|
|
|
|
m_fFogColor[1] = (float)((unsigned char) (((unsigned short) (rgb)) >> 8))/255;
|
|
|
|
m_fFogColor[2] = (float)((unsigned char) ((rgb) >> 16))/255;
|
|
|
|
|
|
|
|
if (fv < 1.0f)
|
|
|
|
{
|
|
|
|
file->ReadLong (&rgb, 1);
|
|
|
|
m_fFogDensity = (float)rgb/100;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
file->ReadFloat (&m_fFogDensity, 1);
|
|
|
|
|
|
|
|
if (fv < 1.3f)
|
|
|
|
{
|
|
|
|
file->ReadByte (&ch, 1);
|
|
|
|
if (ch == 0xFF)
|
|
|
|
file->ReadShort (&sh, 1);
|
|
|
|
sh = ch;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
file->ReadShort (&sh, 1);
|
|
|
|
|
|
|
|
if (sh < LC_MAXPATH)
|
|
|
|
file->Read (m_strBackground, sh);
|
|
|
|
else
|
|
|
|
file->Seek (sh, SEEK_CUR);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (fv >= 0.8f)
|
|
|
|
{
|
|
|
|
file->Read(&ch, 1);
|
|
|
|
file->Read(m_strHeader, ch);
|
|
|
|
file->Read(&ch, 1);
|
|
|
|
file->Read(m_strFooter, ch);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (fv > 0.9f)
|
|
|
|
{
|
|
|
|
file->ReadLong (&rgb, 1);
|
|
|
|
m_fAmbient[0] = (float)((unsigned char) (rgb))/255;
|
|
|
|
m_fAmbient[1] = (float)((unsigned char) (((unsigned short) (rgb)) >> 8))/255;
|
|
|
|
m_fAmbient[2] = (float)((unsigned char) ((rgb) >> 16))/255;
|
|
|
|
|
|
|
|
if (fv < 1.3f)
|
|
|
|
{
|
|
|
|
file->ReadLong (&i, 1); m_bAnimation = (i != 0);
|
|
|
|
file->ReadLong (&i, 1); m_bAddKeys = (i != 0);
|
|
|
|
file->ReadByte (&m_nFPS, 1);
|
|
|
|
file->ReadLong (&i, 1); m_nCurFrame = i;
|
|
|
|
file->ReadShort (&m_nTotalFrames, 1);
|
|
|
|
file->ReadLong (&i, 1); m_nGridSize = i;
|
|
|
|
file->ReadLong (&i, 1); //m_nMoveSnap = i;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
file->ReadByte (&ch, 1); m_bAnimation = (ch != 0);
|
|
|
|
file->ReadByte (&ch, 1); m_bAddKeys = (ch != 0);
|
|
|
|
file->ReadByte (&m_nFPS, 1);
|
|
|
|
file->ReadShort (&m_nCurFrame, 1);
|
|
|
|
file->ReadShort (&m_nTotalFrames, 1);
|
|
|
|
file->ReadShort (&m_nGridSize, 1);
|
|
|
|
file->ReadShort (&sh, 1);
|
|
|
|
if (fv >= 1.4f)
|
|
|
|
m_nMoveSnap = sh;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (fv > 1.0f)
|
|
|
|
{
|
|
|
|
file->ReadLong (&rgb, 1);
|
|
|
|
m_fGradient1[0] = (float)((unsigned char) (rgb))/255;
|
|
|
|
m_fGradient1[1] = (float)((unsigned char) (((unsigned short) (rgb)) >> 8))/255;
|
|
|
|
m_fGradient1[2] = (float)((unsigned char) ((rgb) >> 16))/255;
|
|
|
|
file->ReadLong (&rgb, 1);
|
|
|
|
m_fGradient2[0] = (float)((unsigned char) (rgb))/255;
|
|
|
|
m_fGradient2[1] = (float)((unsigned char) (((unsigned short) (rgb)) >> 8))/255;
|
|
|
|
m_fGradient2[2] = (float)((unsigned char) ((rgb) >> 16))/255;
|
|
|
|
|
|
|
|
if (fv > 1.1f)
|
|
|
|
m_pTerrain->FileLoad (file);
|
|
|
|
else
|
|
|
|
{
|
|
|
|
file->Seek (4, SEEK_CUR);
|
|
|
|
file->Read (&ch, 1);
|
|
|
|
file->Seek (ch, SEEK_CUR);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < m_ViewList.GetSize (); i++)
|
|
|
|
{
|
|
|
|
m_ViewList[i]->MakeCurrent ();
|
|
|
|
RenderInitialize();
|
|
|
|
}
|
|
|
|
CalculateStep();
|
|
|
|
if (!bUndo)
|
|
|
|
SelectAndFocusNone(false);
|
|
|
|
if (!bMerge)
|
|
|
|
SystemUpdateFocus(NULL);
|
|
|
|
SetAction(action);
|
|
|
|
SystemUpdateViewport(m_nViewportMode, 0);
|
|
|
|
SystemUpdateColorList(m_nCurColor);
|
|
|
|
SystemUpdateAnimation(m_bAnimation, m_bAddKeys);
|
2011-09-20 01:03:28 +02:00
|
|
|
SystemUpdateRenderingMode((m_nDetail & LC_DET_FAST) != 0);
|
2011-09-07 23:06:51 +02:00
|
|
|
SystemUpdateSnap(m_nSnap);
|
|
|
|
SystemUpdateSnap(m_nMoveSnap, m_nAngleSnap);
|
|
|
|
SystemUpdateCameraMenu(m_pCameras);
|
|
|
|
SystemUpdateCurrentCamera(NULL, m_pViewCameras[m_nActiveViewport], m_pCameras);
|
|
|
|
UpdateSelection();
|
|
|
|
if (m_bAnimation)
|
|
|
|
SystemUpdateTime(m_bAnimation, m_nCurFrame, m_nTotalFrames);
|
|
|
|
else
|
|
|
|
SystemUpdateTime(m_bAnimation, m_nCurStep, 255);
|
|
|
|
UpdateAllViews ();
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Project::FileSave(File* file, bool bUndo)
|
|
|
|
{
|
|
|
|
float ver_flt = 1.4f; // LeoCAD 0.75 - (and this should have been an integer).
|
|
|
|
unsigned long rgb;
|
|
|
|
unsigned char ch;
|
|
|
|
unsigned short sh;
|
|
|
|
int i, j;
|
|
|
|
|
|
|
|
file->Seek (0, SEEK_SET);
|
|
|
|
file->Write (LC_STR_VERSION, 32);
|
|
|
|
file->WriteFloat (&ver_flt, 1);
|
|
|
|
|
|
|
|
rgb = FLOATRGB(m_fBackground);
|
|
|
|
file->WriteLong (&rgb, 1);
|
|
|
|
|
|
|
|
i = m_nAngleSnap; file->WriteLong (&i, 1);
|
|
|
|
file->WriteLong (&m_nSnap, 1);
|
|
|
|
file->WriteFloat (&m_fLineWidth, 1);
|
|
|
|
file->WriteLong (&m_nDetail, 1);
|
|
|
|
//i = m_nCurGroup;
|
|
|
|
file->WriteLong (&i, 1);
|
|
|
|
i = m_nCurColor; file->WriteLong (&i, 1);
|
|
|
|
i = m_nCurAction; file->WriteLong (&i, 1);
|
|
|
|
i = m_nCurStep; file->WriteLong (&i, 1);
|
|
|
|
file->WriteLong (&m_nScene, 1);
|
|
|
|
|
|
|
|
Piece* pPiece;
|
|
|
|
for (i = 0, pPiece = m_pPieces; pPiece; pPiece = pPiece->m_pNext)
|
|
|
|
i++;
|
|
|
|
file->WriteLong (&i, 1);
|
|
|
|
|
|
|
|
for (pPiece = m_pPieces; pPiece; pPiece = pPiece->m_pNext)
|
|
|
|
pPiece->FileSave (*file, m_pGroups);
|
|
|
|
|
|
|
|
ch = strlen(m_strAuthor);
|
|
|
|
file->Write(&ch, 1);
|
|
|
|
file->Write(m_strAuthor, ch);
|
|
|
|
ch = strlen(m_strDescription);
|
|
|
|
file->Write(&ch, 1);
|
|
|
|
file->Write(m_strDescription, ch);
|
|
|
|
ch = strlen(m_strComments);
|
|
|
|
file->Write(&ch, 1);
|
|
|
|
file->Write(m_strComments, ch);
|
|
|
|
|
|
|
|
Group* pGroup;
|
|
|
|
for (i = 0, pGroup = m_pGroups; pGroup; pGroup = pGroup->m_pNext)
|
|
|
|
i++;
|
|
|
|
file->WriteLong (&i, 1);
|
|
|
|
|
|
|
|
for (pGroup = m_pGroups; pGroup; pGroup = pGroup->m_pNext)
|
|
|
|
pGroup->FileSave(file, m_pGroups);
|
|
|
|
|
|
|
|
file->WriteByte (&m_nViewportMode, 1);
|
|
|
|
file->WriteByte (&m_nActiveViewport, 1);
|
|
|
|
|
|
|
|
Camera* pCamera;
|
|
|
|
for (i = 0, pCamera = m_pCameras; pCamera; pCamera = pCamera->m_pNext)
|
|
|
|
i++;
|
|
|
|
file->WriteLong (&i, 1);
|
|
|
|
|
|
|
|
for (i = 0, pCamera = m_pCameras; pCamera; pCamera = pCamera->m_pNext)
|
|
|
|
pCamera->FileSave(*file);
|
|
|
|
|
|
|
|
for (j = 0; j < 4; j++)
|
|
|
|
{
|
|
|
|
for (i = 0, pCamera = m_pCameras; pCamera; pCamera = pCamera->m_pNext)
|
|
|
|
if (pCamera == m_pViewCameras[j])
|
|
|
|
break;
|
|
|
|
else
|
|
|
|
i++;
|
|
|
|
|
|
|
|
file->WriteLong (&i, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
rgb = FLOATRGB(m_fFogColor);
|
|
|
|
file->WriteLong (&rgb, 1);
|
|
|
|
file->WriteFloat (&m_fFogDensity, 1);
|
|
|
|
sh = strlen(m_strBackground);
|
|
|
|
file->WriteShort (&sh, 1);
|
|
|
|
file->Write(m_strBackground, sh);
|
|
|
|
ch = strlen(m_strHeader);
|
|
|
|
file->Write(&ch, 1);
|
|
|
|
file->Write(m_strHeader, ch);
|
|
|
|
ch = strlen(m_strFooter);
|
|
|
|
file->Write(&ch, 1);
|
|
|
|
file->Write(m_strFooter, ch);
|
|
|
|
// 0.60 (1.0)
|
|
|
|
rgb = FLOATRGB(m_fAmbient);
|
|
|
|
file->WriteLong (&rgb, 1);
|
|
|
|
ch = m_bAnimation;
|
|
|
|
file->Write(&ch, 1);
|
|
|
|
ch = m_bAddKeys;
|
|
|
|
file->WriteByte (&ch, 1);
|
|
|
|
file->WriteByte (&m_nFPS, 1);
|
|
|
|
file->WriteShort (&m_nCurFrame, 1);
|
|
|
|
file->WriteShort (&m_nTotalFrames, 1);
|
|
|
|
file->WriteShort (&m_nGridSize, 1);
|
|
|
|
file->WriteShort (&m_nMoveSnap, 1);
|
|
|
|
// 0.62 (1.1)
|
|
|
|
rgb = FLOATRGB(m_fGradient1);
|
|
|
|
file->WriteLong (&rgb, 1);
|
|
|
|
rgb = FLOATRGB(m_fGradient2);
|
|
|
|
file->WriteLong (&rgb, 1);
|
|
|
|
// 0.64 (1.2)
|
|
|
|
m_pTerrain->FileSave(file);
|
|
|
|
|
|
|
|
if (!bUndo)
|
|
|
|
{
|
|
|
|
unsigned long pos = 0;
|
|
|
|
|
|
|
|
i = Sys_ProfileLoadInt ("Default", "Save Preview", 0);
|
|
|
|
if (i != 0)
|
|
|
|
{
|
|
|
|
pos = file->GetPosition();
|
|
|
|
|
|
|
|
Image* image = new Image[1];
|
|
|
|
LC_IMAGE_OPTS opts;
|
|
|
|
opts.interlaced = false;
|
|
|
|
opts.transparent = false;
|
|
|
|
opts.format = LC_IMAGE_GIF;
|
|
|
|
|
|
|
|
i = m_bAnimation ? m_nCurFrame : m_nCurStep;
|
|
|
|
CreateImages(image, 120, 100, i, i, false);
|
|
|
|
image[0].FileSave (*file, &opts);
|
|
|
|
delete []image;
|
|
|
|
}
|
|
|
|
|
|
|
|
file->WriteLong (&pos, 1);
|
|
|
|
m_nSaveTimer = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Project::FileReadMPD(File& MPD, PtrArray<File>& FileArray) const
|
|
|
|
{
|
|
|
|
FileMem* CurFile = NULL;
|
|
|
|
char Buf[1024];
|
|
|
|
|
|
|
|
while (MPD.ReadLine(Buf, 1024))
|
|
|
|
{
|
|
|
|
String Line(Buf);
|
|
|
|
|
|
|
|
Line.TrimLeft();
|
|
|
|
|
|
|
|
if (Line[0] != '0')
|
|
|
|
{
|
|
|
|
// Copy current line.
|
|
|
|
if (CurFile != NULL)
|
|
|
|
CurFile->Write(Buf, strlen(Buf));
|
|
|
|
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
Line.TrimRight();
|
|
|
|
Line = Line.Right(Line.GetLength() - 1);
|
|
|
|
Line.TrimLeft();
|
|
|
|
|
|
|
|
// Find where a subfile starts.
|
|
|
|
if (Line.CompareNoCase("FILE", 4) == 0)
|
|
|
|
{
|
|
|
|
Line = Line.Right(Line.GetLength() - 4);
|
|
|
|
Line.TrimLeft();
|
|
|
|
|
|
|
|
// Create a new file.
|
|
|
|
CurFile = new FileMem();
|
|
|
|
CurFile->SetFileName(Line);
|
|
|
|
FileArray.Add(CurFile);
|
|
|
|
}
|
|
|
|
else if (Line.CompareNoCase("ENDFILE", 7) == 0)
|
|
|
|
{
|
|
|
|
// File ends here.
|
|
|
|
CurFile = NULL;
|
|
|
|
}
|
|
|
|
else if (CurFile != NULL)
|
|
|
|
{
|
|
|
|
// Copy current line.
|
|
|
|
CurFile->Write(Buf, strlen(Buf));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Project::FileReadLDraw(File* file, Matrix* prevmat, int* nOk, int DefColor, int* nStep, PtrArray<File>& FileArray)
|
|
|
|
{
|
|
|
|
char buf[1024];
|
|
|
|
|
|
|
|
// Save file offset.
|
|
|
|
lcuint32 Offset = file->GetPosition();
|
|
|
|
file->Seek(0, SEEK_SET);
|
|
|
|
|
|
|
|
while (file->ReadLine(buf, 1024))
|
|
|
|
{
|
|
|
|
strupr(buf);
|
|
|
|
if (strstr(buf, "STEP"))
|
|
|
|
{
|
|
|
|
(*nStep)++;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool read = true;
|
|
|
|
char *ptr, tmp[LC_MAXPATH], pn[LC_MAXPATH];
|
|
|
|
int color, cmd;
|
|
|
|
float fmat[12];
|
|
|
|
|
|
|
|
if (sscanf(buf, "%d %d %g %g %g %g %g %g %g %g %g %g %g %g %s[12]",
|
|
|
|
&cmd, &color, &fmat[0], &fmat[1], &fmat[2], &fmat[3], &fmat[4], &fmat[5], &fmat[6],
|
|
|
|
&fmat[7], &fmat[8], &fmat[9], &fmat[10], &fmat[11], &tmp[0]) != 15)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
Matrix incmat, tmpmat;
|
|
|
|
incmat.FromLDraw(fmat);
|
|
|
|
tmpmat.Multiply(*prevmat, incmat);
|
|
|
|
|
|
|
|
if (cmd == 1)
|
|
|
|
{
|
|
|
|
int cl = 0;
|
|
|
|
if (color == 16)
|
|
|
|
cl = DefColor;
|
|
|
|
else
|
|
|
|
cl = ConvertColor(color);
|
|
|
|
|
|
|
|
strcpy(pn, tmp);
|
|
|
|
ptr = strrchr(tmp, '.');
|
|
|
|
|
|
|
|
if (ptr != NULL)
|
|
|
|
*ptr = 0;
|
|
|
|
|
|
|
|
// See if it's a piece in the library
|
|
|
|
if (strlen(tmp) < LC_PIECE_NAME_LEN)
|
|
|
|
{
|
|
|
|
char name[LC_PIECE_NAME_LEN];
|
|
|
|
strcpy(name, tmp);
|
|
|
|
|
|
|
|
PieceInfo* pInfo = lcGetPiecesLibrary()->FindPieceInfo(name);
|
|
|
|
if (pInfo != NULL)
|
|
|
|
{
|
|
|
|
float x, y, z, rot[4];
|
|
|
|
Piece* pPiece = new Piece(pInfo);
|
|
|
|
read = false;
|
|
|
|
|
|
|
|
tmpmat.GetTranslation(&x, &y, &z);
|
|
|
|
pPiece->Initialize(x, y, z, *nStep, 1, cl);
|
|
|
|
pPiece->CreateName(m_pPieces);
|
|
|
|
AddPiece(pPiece);
|
|
|
|
tmpmat.ToAxisAngle(rot);
|
|
|
|
pPiece->ChangeKey(1, false, false, rot, LC_PK_ROTATION);
|
|
|
|
pPiece->ChangeKey(1, true, false, rot, LC_PK_ROTATION);
|
|
|
|
SystemPieceComboAdd(pInfo->m_strDescription);
|
|
|
|
(*nOk)++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check for MPD files first.
|
|
|
|
if (read)
|
|
|
|
{
|
|
|
|
for (int i = 0; i < FileArray.GetSize(); i++)
|
|
|
|
{
|
|
|
|
if (stricmp(FileArray[i]->GetFileName(), pn) == 0)
|
|
|
|
{
|
|
|
|
FileReadLDraw(FileArray[i], &tmpmat, nOk, cl, nStep, FileArray);
|
|
|
|
read = false;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Try to read the file from disk.
|
|
|
|
if (read)
|
|
|
|
{
|
|
|
|
FileDisk tf;
|
|
|
|
|
|
|
|
if (tf.Open(pn, "rt"))
|
|
|
|
{
|
|
|
|
FileReadLDraw(&tf, &tmpmat, nOk, cl, nStep, FileArray);
|
|
|
|
read = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Restore file offset.
|
|
|
|
file->Seek(Offset, SEEK_SET);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Project::DoFileSave()
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
DWORD dwAttrib = GetFileAttributes(m_strPathName);
|
|
|
|
if (dwAttrib & FILE_ATTRIBUTE_READONLY)
|
|
|
|
{
|
|
|
|
// we do not have read-write access or the file does not (now) exist
|
|
|
|
if (!DoSave(NULL, true))
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
*/ {
|
|
|
|
if (!DoSave(m_strPathName, true))
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Save the document data to a file
|
|
|
|
// lpszPathName = path name where to save document file
|
|
|
|
// if lpszPathName is NULL then the user will be prompted (SaveAs)
|
|
|
|
// note: lpszPathName can be different than 'm_strPathName'
|
|
|
|
// if 'bReplace' is TRUE will change file name if successful (SaveAs)
|
|
|
|
// if 'bReplace' is FALSE will not change path name (SaveCopyAs)
|
|
|
|
bool Project::DoSave(char* lpszPathName, bool bReplace)
|
|
|
|
{
|
|
|
|
FileDisk file;
|
|
|
|
char newName[LC_MAXPATH];
|
|
|
|
memset(newName, 0, sizeof(newName));
|
|
|
|
if (lpszPathName)
|
|
|
|
strcpy(newName, lpszPathName);
|
|
|
|
|
|
|
|
char ext[4], *ptr;
|
|
|
|
memset(ext, 0, 4);
|
|
|
|
ptr = strrchr(newName, '.');
|
|
|
|
if (ptr != NULL)
|
|
|
|
{
|
|
|
|
ptr++;
|
|
|
|
strncpy(ext, ptr, 3);
|
|
|
|
strlwr(ext);
|
|
|
|
|
|
|
|
if ((strcmp(ext, "dat") == 0) || (strcmp(ext, "ldr") == 0))
|
|
|
|
{
|
|
|
|
*ptr = 0;
|
|
|
|
strcat(newName, "lcd");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (strlen(newName) == 0)
|
|
|
|
{
|
|
|
|
strcpy(newName, m_strPathName);
|
|
|
|
if (bReplace && strlen(newName) == 0)
|
|
|
|
{
|
|
|
|
strcpy(newName, m_strTitle);
|
|
|
|
|
|
|
|
// check for dubious filename
|
|
|
|
int iBad = strcspn(newName, " #%;/\\");
|
|
|
|
if (iBad != -1)
|
|
|
|
newName[iBad] = 0;
|
|
|
|
|
|
|
|
strcat(newName, ".lcd");
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!SystemDoDialog(LC_DLG_FILE_SAVE_PROJECT, &newName))
|
|
|
|
return false; // don't even attempt to save
|
|
|
|
}
|
|
|
|
|
|
|
|
// CWaitCursor wait;
|
|
|
|
|
|
|
|
if (!file.Open(newName, "wb"))
|
|
|
|
{
|
|
|
|
// MessageBox("Failed to save.");
|
|
|
|
|
|
|
|
// be sure to delete the file
|
|
|
|
if (lpszPathName == NULL)
|
|
|
|
remove(newName);
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
memset(ext, 0, 4);
|
|
|
|
ptr = strrchr(newName, '.');
|
|
|
|
if (ptr != NULL)
|
|
|
|
{
|
|
|
|
strncpy(ext, ptr+1, 3);
|
|
|
|
strlwr(ext);
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((strcmp(ext, "dat") == 0) || (strcmp(ext, "ldr") == 0))
|
|
|
|
{
|
|
|
|
const int col[28] = { 4,12,2,10,1,9,14,15,8,0,6,13,13,334,36,44,34,42,33,41,46,47,7,382,6,13,11,383 };
|
|
|
|
Piece* pPiece;
|
|
|
|
int i, steps = GetLastStep();
|
|
|
|
char buf[256], *ptr;
|
|
|
|
|
|
|
|
ptr = strrchr(m_strPathName, '\\');
|
|
|
|
if (ptr == NULL)
|
|
|
|
ptr = strrchr(m_strPathName, '/');
|
|
|
|
if (ptr == NULL)
|
|
|
|
ptr = m_strPathName;
|
|
|
|
else
|
|
|
|
ptr++;
|
|
|
|
|
|
|
|
sprintf(buf, "0 Model exported from LeoCAD\r\n"
|
|
|
|
"0 Original name: %s\r\n", ptr);
|
|
|
|
if (strlen(m_strAuthor) != 0)
|
|
|
|
{
|
|
|
|
strcat(buf, "0 Author: ");
|
|
|
|
strcat(buf, m_strAuthor);
|
|
|
|
strcat(buf, "\r\n");
|
|
|
|
}
|
|
|
|
strcat(buf, "\r\n");
|
|
|
|
file.Write(buf, strlen(buf));
|
|
|
|
|
|
|
|
for (i = 1; i <= steps; i++)
|
|
|
|
{
|
|
|
|
for (pPiece = m_pPieces; pPiece; pPiece = pPiece->m_pNext)
|
|
|
|
{
|
|
|
|
if ((pPiece->IsVisible(i, false)) && (pPiece->GetStepShow() == i))
|
|
|
|
{
|
|
|
|
float f[12], position[3], rotation[4];
|
|
|
|
pPiece->GetPosition(position);
|
|
|
|
pPiece->GetRotation(rotation);
|
|
|
|
Matrix mat(rotation, position);
|
|
|
|
mat.ToLDraw(f);
|
|
|
|
sprintf (buf, " 1 %d %.2f %.2f %.2f %.2f %.2f %.2f %.2f %.2f %.2f %.2f %.2f %.2f %s.DAT\r\n",
|
|
|
|
col[pPiece->GetColor()], f[0], f[1], f[2], f[3], f[4], f[5], f[6], f[7], f[8], f[9], f[10], f[11], pPiece->GetPieceInfo()->m_strName);
|
|
|
|
file.Write(buf, strlen(buf));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (i != steps)
|
|
|
|
file.Write("0 STEP\r\n", 8);
|
|
|
|
}
|
|
|
|
file.Write("0\r\n", 3);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
FileSave(&file, false); // save me
|
|
|
|
file.Close();
|
|
|
|
|
|
|
|
SetModifiedFlag(false); // back to unmodified
|
|
|
|
|
|
|
|
// reset the title and change the document name
|
|
|
|
if (bReplace)
|
|
|
|
SetPathName(newName, true);
|
|
|
|
|
|
|
|
return true; // success
|
|
|
|
}
|
|
|
|
|
|
|
|
// return true if ok to continue
|
|
|
|
bool Project::SaveModified()
|
|
|
|
{
|
|
|
|
if (!IsModified())
|
|
|
|
return true; // ok to continue
|
|
|
|
|
|
|
|
// get name/title of document
|
|
|
|
char name[LC_MAXPATH];
|
|
|
|
if (strlen(m_strPathName) == 0)
|
|
|
|
{
|
|
|
|
// get name based on caption
|
|
|
|
strcpy(name, m_strTitle);
|
|
|
|
if (strlen(name) == 0)
|
|
|
|
strcpy(name, "Untitled");
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// get name based on file title of path name
|
|
|
|
char* p;
|
|
|
|
|
|
|
|
p = strrchr(m_strPathName, '\\');
|
|
|
|
if (!p)
|
|
|
|
p = strrchr(m_strPathName, '/');
|
|
|
|
|
|
|
|
if (p)
|
|
|
|
strcpy(name, ++p);
|
|
|
|
else
|
|
|
|
strcpy(name, m_strPathName);
|
|
|
|
}
|
|
|
|
|
|
|
|
char prompt[512];
|
|
|
|
sprintf(prompt, "Save changes to %s ?", name);
|
|
|
|
|
|
|
|
switch (SystemDoMessageBox(prompt, LC_MB_YESNOCANCEL))
|
|
|
|
{
|
|
|
|
case LC_CANCEL:
|
|
|
|
return false; // don't continue
|
|
|
|
|
|
|
|
case LC_YES:
|
|
|
|
// If so, either Save or Update, as appropriate
|
|
|
|
if (!DoFileSave())
|
|
|
|
return false; // don't continue
|
|
|
|
break;
|
|
|
|
|
|
|
|
case LC_NO:
|
|
|
|
// If not saving changes, revert the document
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true; // keep going
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
// File operations
|
|
|
|
|
|
|
|
bool Project::OnNewDocument()
|
|
|
|
{
|
|
|
|
SetTitle("Untitled");
|
|
|
|
DeleteContents(false);
|
|
|
|
memset(m_strPathName, 0, sizeof(m_strPathName)); // no path name yet
|
|
|
|
strcpy(m_strAuthor, Sys_ProfileLoadString ("Default", "User", ""));
|
|
|
|
SetModifiedFlag(false); // make clean
|
|
|
|
LoadDefaults(true);
|
|
|
|
CheckPoint("");
|
|
|
|
|
|
|
|
// SystemUpdateRecentMenu(m_strRecentFiles);
|
|
|
|
messenger->Dispatch (LC_MSG_FOCUS_CHANGED, NULL);
|
|
|
|
|
|
|
|
// CWnd* pFrame = AfxGetMainWnd();
|
|
|
|
// if (pFrame != NULL)
|
|
|
|
// pFrame->PostMessage (WM_LC_UPDATE_LIST, 1, m_nCurColor+1);
|
|
|
|
// set cur group to 0
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Project::OpenProject(const char* FileName)
|
|
|
|
{
|
|
|
|
if (!SaveModified())
|
|
|
|
return false; // Leave the original one
|
|
|
|
|
|
|
|
// CWaitCursor wait;
|
|
|
|
bool WasModified = IsModified();
|
|
|
|
SetModifiedFlag(false); // Not dirty for open
|
|
|
|
|
|
|
|
if (!OnOpenDocument(FileName))
|
|
|
|
{
|
|
|
|
// Check if we corrupted the original document
|
|
|
|
if (!IsModified())
|
|
|
|
SetModifiedFlag(WasModified);
|
|
|
|
else
|
|
|
|
OnNewDocument();
|
|
|
|
|
|
|
|
return false; // Open failed
|
|
|
|
}
|
|
|
|
|
|
|
|
SetPathName(FileName, true);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Project::OnOpenDocument (const char* lpszPathName)
|
|
|
|
{
|
|
|
|
FileDisk file;
|
|
|
|
bool bSuccess = false;
|
|
|
|
|
|
|
|
if (!file.Open(lpszPathName, "rb"))
|
|
|
|
{
|
|
|
|
// MessageBox("Failed to open file.");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
char ext[4];
|
|
|
|
const char *ptr;
|
|
|
|
memset(ext, 0, 4);
|
|
|
|
ptr = strrchr(lpszPathName, '.');
|
|
|
|
if (ptr != NULL)
|
|
|
|
{
|
|
|
|
strncpy(ext, ptr+1, 3);
|
|
|
|
strlwr(ext);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool datfile = false;
|
|
|
|
bool mpdfile = false;
|
|
|
|
|
|
|
|
// Find out what file type we're loading.
|
|
|
|
if ((strcmp(ext, "dat") == 0) || (strcmp(ext, "ldr") == 0))
|
|
|
|
datfile = true;
|
|
|
|
else if (strcmp(ext, "mpd") == 0)
|
|
|
|
mpdfile = true;
|
|
|
|
|
|
|
|
// Delete the current project.
|
|
|
|
DeleteContents(false);
|
|
|
|
LoadDefaults(datfile || mpdfile);
|
|
|
|
SetModifiedFlag(true); // dirty during loading
|
|
|
|
|
|
|
|
SystemDoWaitCursor(1);
|
|
|
|
|
|
|
|
if (file.GetLength() != 0)
|
|
|
|
{
|
|
|
|
PtrArray<File> FileArray;
|
|
|
|
|
|
|
|
// Unpack the MPD file.
|
|
|
|
if (mpdfile)
|
|
|
|
{
|
|
|
|
FileReadMPD(file, FileArray);
|
|
|
|
|
|
|
|
if (FileArray.GetSize() == 0)
|
|
|
|
{
|
|
|
|
file.Seek(0, SEEK_SET);
|
|
|
|
mpdfile = false;
|
|
|
|
datfile = true;
|
|
|
|
console.PrintWarning("No files found inside the MPD, trying to load it as a .DAT file.\n");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (datfile || mpdfile)
|
|
|
|
{
|
|
|
|
int ok = 0, step = 1;
|
|
|
|
Matrix mat;
|
|
|
|
|
|
|
|
if (mpdfile)
|
|
|
|
FileReadLDraw(FileArray[0], &mat, &ok, m_nCurColor, &step, FileArray);
|
|
|
|
else
|
|
|
|
FileReadLDraw(&file, &mat, &ok, m_nCurColor, &step, FileArray);
|
|
|
|
|
|
|
|
m_nCurStep = step;
|
|
|
|
SystemUpdateTime(false, m_nCurStep, 255);
|
|
|
|
SystemUpdateFocus(NULL);
|
|
|
|
UpdateSelection();
|
|
|
|
CalculateStep();
|
|
|
|
UpdateAllViews ();
|
|
|
|
|
|
|
|
console.PrintMisc("%d objects imported.\n", ok);
|
|
|
|
bSuccess = true;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// Load a LeoCAD file.
|
|
|
|
bSuccess = FileLoad(&file, false, false);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Clean up.
|
|
|
|
if (mpdfile)
|
|
|
|
{
|
|
|
|
for (int i = 0; i < FileArray.GetSize(); i++)
|
|
|
|
delete FileArray[i];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
file.Close();
|
|
|
|
SystemDoWaitCursor(-1);
|
|
|
|
|
|
|
|
if (bSuccess == false)
|
|
|
|
{
|
|
|
|
// MessageBox("Failed to load.");
|
|
|
|
DeleteContents(false); // remove failed contents
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
CheckPoint("");
|
|
|
|
m_nSaveTimer = 0;
|
|
|
|
|
|
|
|
SetModifiedFlag(false); // start off with unmodified
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Project::SetPathName(const char* lpszPathName, bool bAddToMRU)
|
|
|
|
{
|
|
|
|
strcpy(m_strPathName, lpszPathName);
|
|
|
|
|
|
|
|
// always capture the complete file name including extension (if present)
|
|
|
|
const char* lpszTemp = lpszPathName;
|
|
|
|
for (const char* lpsz = lpszPathName; *lpsz != '\0'; lpsz++)
|
|
|
|
{
|
|
|
|
// remember last directory/drive separator
|
|
|
|
if (*lpsz == '\\' || *lpsz == '/' || *lpsz == ':')
|
|
|
|
lpszTemp = lpsz + 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
// set the document title based on path name
|
|
|
|
SetTitle(lpszTemp);
|
|
|
|
|
|
|
|
// add it to the file MRU list
|
|
|
|
if (bAddToMRU)
|
|
|
|
main_window->AddToMRU (lpszPathName);
|
|
|
|
}
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
// Undo/Redo support
|
|
|
|
|
|
|
|
// Save current state.
|
|
|
|
void Project::CheckPoint (const char* text)
|
|
|
|
{
|
|
|
|
LC_UNDOINFO* pTmp;
|
|
|
|
LC_UNDOINFO* pUndo = new LC_UNDOINFO;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
strcpy(pUndo->strText, text);
|
|
|
|
FileSave(&pUndo->file, true);
|
|
|
|
|
|
|
|
for (pTmp = m_pUndoList, i = 0; pTmp; pTmp = pTmp->pNext, i++)
|
|
|
|
if ((i == 30) && (pTmp->pNext != NULL))
|
|
|
|
{
|
|
|
|
delete pTmp->pNext;
|
|
|
|
pTmp->pNext = NULL;
|
|
|
|
m_bUndoOriginal = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
pUndo->pNext = m_pUndoList;
|
|
|
|
m_pUndoList = pUndo;
|
|
|
|
|
|
|
|
while (m_pRedoList)
|
|
|
|
{
|
|
|
|
pUndo = m_pRedoList;
|
|
|
|
m_pRedoList = m_pRedoList->pNext;
|
|
|
|
delete pUndo;
|
|
|
|
}
|
|
|
|
m_pRedoList = NULL;
|
|
|
|
|
|
|
|
SystemUpdateUndoRedo(m_pUndoList->pNext ? m_pUndoList->strText : NULL, NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Project::AddView (View* pView)
|
|
|
|
{
|
2011-09-17 01:59:55 +02:00
|
|
|
m_ViewList.Add (pView);
|
2011-09-07 23:06:51 +02:00
|
|
|
|
2011-09-17 01:59:55 +02:00
|
|
|
pView->MakeCurrent ();
|
|
|
|
RenderInitialize ();
|
2011-09-07 23:06:51 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void Project::RemoveView (View* pView)
|
|
|
|
{
|
2011-09-17 01:59:55 +02:00
|
|
|
if (pView == m_ActiveView)
|
|
|
|
m_ActiveView = NULL;
|
|
|
|
|
|
|
|
m_ViewList.RemovePointer(pView);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Project::UpdateAllViews()
|
|
|
|
{
|
|
|
|
for (int i = 0; i < m_ViewList.GetSize (); i++)
|
|
|
|
m_ViewList[i]->Redraw ();
|
2011-09-07 23:06:51 +02:00
|
|
|
}
|
|
|
|
|
2011-09-17 01:59:55 +02:00
|
|
|
void Project::SetActiveView(View* view)
|
2011-09-07 23:06:51 +02:00
|
|
|
{
|
2011-09-17 01:59:55 +02:00
|
|
|
if (view == m_ActiveView)
|
|
|
|
return;
|
|
|
|
|
|
|
|
// Camera* OldCamera = NULL;
|
|
|
|
View* OldView = m_ActiveView;
|
|
|
|
m_ActiveView = view;
|
|
|
|
|
|
|
|
if (OldView)
|
|
|
|
{
|
|
|
|
OldView->Redraw();
|
|
|
|
// OldCamera = OldView->GetCamera();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (view)
|
|
|
|
{
|
|
|
|
view->Redraw();
|
|
|
|
// SystemUpdateCurrentCamera(OldCamera, m_ActiveView->GetCamera(), m_ActiveModel->m_Cameras);
|
|
|
|
}
|
2011-09-07 23:06:51 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
// Project rendering
|
|
|
|
|
|
|
|
// Only this function should be called.
|
|
|
|
void Project::Render(bool bToMemory)
|
|
|
|
{
|
|
|
|
if (bToMemory)
|
|
|
|
{
|
|
|
|
// m_bDenyRender = TRUE;
|
|
|
|
// m_bRendering = TRUE;
|
|
|
|
RenderScene(true, false);
|
|
|
|
// m_bRendering = FALSE;
|
|
|
|
// m_bDenyRender = FALSE;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// if (m_bDenyRender)
|
|
|
|
// return;
|
|
|
|
|
|
|
|
#ifdef _DEBUG
|
|
|
|
#ifdef LC_WINDOWS
|
|
|
|
#define BENCHMARK
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef BENCHMARK
|
|
|
|
DWORD dwMillis = GetTickCount();
|
|
|
|
#endif
|
|
|
|
|
|
|
|
m_bStopRender = false;
|
|
|
|
m_bRendering = true;
|
|
|
|
|
|
|
|
if ((m_nDetail & LC_DET_FAST) && (m_nTracking != LC_TRACK_NONE))
|
|
|
|
RenderScene(false, true);
|
|
|
|
else
|
|
|
|
RenderScene(true, true);
|
|
|
|
|
|
|
|
m_bRendering = false;
|
|
|
|
|
|
|
|
#ifdef BENCHMARK
|
|
|
|
dwMillis = GetTickCount() - dwMillis;
|
|
|
|
char szMsg[30];
|
|
|
|
static int FrameCount = 0;
|
|
|
|
FrameCount++;
|
|
|
|
sprintf(szMsg, "%d - %.4f sec", FrameCount, (float)dwMillis/1000);
|
|
|
|
AfxGetMainWnd()->SetWindowText(szMsg);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
typedef struct LC_BSPNODE
|
|
|
|
{
|
|
|
|
float plane[4];
|
|
|
|
Piece* piece;
|
|
|
|
LC_BSPNODE* front;
|
|
|
|
LC_BSPNODE* back;
|
|
|
|
|
|
|
|
~LC_BSPNODE()
|
|
|
|
{
|
|
|
|
if (piece == NULL)
|
|
|
|
{
|
|
|
|
if (front)
|
|
|
|
delete front;
|
|
|
|
if (back)
|
|
|
|
delete back;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} LC_BSPNODE;
|
|
|
|
|
|
|
|
static void RenderBSP(LC_BSPNODE* node, float* eye, bool* bSel,
|
|
|
|
bool bLighting, bool bEdges, unsigned char* nLastColor, bool* bTrans)
|
|
|
|
{
|
|
|
|
if (node->piece)
|
|
|
|
{
|
|
|
|
if (node->piece->IsSelected())
|
|
|
|
{
|
|
|
|
if (!*bSel)
|
|
|
|
{
|
|
|
|
*bSel = true;
|
|
|
|
glLineWidth (2);//*m_fLineWidth);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (*bSel)
|
|
|
|
{
|
|
|
|
*bSel = false;
|
|
|
|
glLineWidth(1);//m_fLineWidth);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
node->piece->Render(bLighting, bEdges, nLastColor, bTrans);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (eye[0]*node->plane[0] + eye[1]*node->plane[1] +
|
|
|
|
eye[2]*node->plane[2] + node->plane[3] > 0.0f)
|
|
|
|
{
|
|
|
|
RenderBSP(node->back, eye, bSel, bLighting, bEdges, nLastColor, bTrans);
|
|
|
|
RenderBSP(node->front, eye, bSel, bLighting, bEdges, nLastColor, bTrans);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
RenderBSP(node->front, eye, bSel, bLighting, bEdges, nLastColor, bTrans);
|
|
|
|
RenderBSP(node->back, eye, bSel, bLighting, bEdges, nLastColor, bTrans);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void BuildBSP(LC_BSPNODE* node, Piece* pList)
|
|
|
|
{
|
|
|
|
Piece *front_list = NULL, *back_list = NULL;
|
|
|
|
Piece *pPiece, *pNext;
|
|
|
|
|
|
|
|
node->piece = NULL;
|
|
|
|
|
|
|
|
if (pList->m_pLink == NULL)
|
|
|
|
{
|
|
|
|
// This is a leaf
|
|
|
|
node->piece = pList;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
float dx, dy, dz, bs[6] = { 10000, 10000, 10000, -10000, -10000, -10000 };
|
|
|
|
const float *pos;
|
|
|
|
|
|
|
|
for (pPiece = pList; pPiece; pPiece = pPiece->m_pLink)
|
|
|
|
{
|
|
|
|
pos = pPiece->GetConstPosition();
|
|
|
|
if (pos[0] < bs[0]) bs[0] = pos[0];
|
|
|
|
if (pos[1] < bs[1]) bs[1] = pos[1];
|
|
|
|
if (pos[2] < bs[2]) bs[2] = pos[2];
|
|
|
|
if (pos[0] > bs[3]) bs[3] = pos[0];
|
|
|
|
if (pos[1] > bs[4]) bs[4] = pos[1];
|
|
|
|
if (pos[2] > bs[5]) bs[5] = pos[2];
|
|
|
|
}
|
|
|
|
|
|
|
|
dx = ABS(bs[0]-bs[3]);
|
|
|
|
dy = ABS(bs[1]-bs[4]);
|
|
|
|
dz = ABS(bs[2]-bs[5]);
|
|
|
|
|
|
|
|
node->plane[0] = node->plane[1] = node->plane[2] = 0.0f;
|
|
|
|
|
|
|
|
if (dx > dy)
|
|
|
|
{
|
|
|
|
if (dx > dz)
|
|
|
|
node->plane[0] = 1.0f;
|
|
|
|
else
|
|
|
|
node->plane[2] = 1.0f;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (dy > dz)
|
|
|
|
node->plane[1] = 1.0f;
|
|
|
|
else
|
|
|
|
node->plane[2] = 1.0f;
|
|
|
|
}
|
|
|
|
|
|
|
|
// D = -Ax -By -Cz
|
|
|
|
node->plane[3] = -(node->plane[0]*(bs[0]+bs[3])/2)-(node->plane[1]*(bs[1]+bs[4])/2)-(node->plane[2]*(bs[2]+bs[5])/2);
|
|
|
|
|
|
|
|
for (pPiece = pList; pPiece;)
|
|
|
|
{
|
|
|
|
pos = pPiece->GetConstPosition();
|
|
|
|
pNext = pPiece->m_pLink;
|
|
|
|
|
|
|
|
if (pos[0]*node->plane[0] + pos[1]*node->plane[1] +
|
|
|
|
pos[2]*node->plane[2] + node->plane[3] > 0.0f)
|
|
|
|
{
|
|
|
|
pPiece->m_pLink = front_list;
|
|
|
|
front_list = pPiece;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
pPiece->m_pLink = back_list;
|
|
|
|
back_list = pPiece;
|
|
|
|
}
|
|
|
|
|
|
|
|
pPiece = pNext;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (bs[0] == bs[3] && bs[1] == bs[4] && bs[2] == bs[5])
|
|
|
|
{
|
|
|
|
if (back_list)
|
|
|
|
{
|
|
|
|
front_list = back_list;
|
|
|
|
back_list = back_list->m_pLink;
|
|
|
|
front_list->m_pLink = NULL;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
back_list = front_list;
|
|
|
|
front_list = front_list->m_pLink;
|
|
|
|
back_list->m_pLink = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (front_list)
|
|
|
|
{
|
|
|
|
node->front = new LC_BSPNODE;
|
|
|
|
BuildBSP(node->front, front_list);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
node->front = NULL;
|
|
|
|
|
|
|
|
if (back_list)
|
|
|
|
{
|
|
|
|
node->back = new LC_BSPNODE;
|
|
|
|
BuildBSP(node->back, back_list);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
node->back = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Project::RenderScene(bool bShaded, bool bDrawViewports)
|
|
|
|
{
|
|
|
|
glViewport (0, 0, m_nViewX, m_nViewY);
|
|
|
|
glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
|
|
|
|
|
|
|
if (bDrawViewports)
|
|
|
|
{
|
|
|
|
if (bShaded)
|
|
|
|
{
|
|
|
|
if (m_nDetail & LC_DET_LIGHTING)
|
|
|
|
glDisable (GL_LIGHTING);
|
|
|
|
if (m_nScene & LC_SCENE_FOG)
|
|
|
|
glDisable (GL_FOG);
|
|
|
|
RenderViewports(true, true);
|
|
|
|
if (m_nDetail & LC_DET_LIGHTING)
|
|
|
|
glEnable(GL_LIGHTING);
|
|
|
|
if (m_nScene & LC_SCENE_FOG)
|
|
|
|
glEnable (GL_FOG);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
RenderViewports(true, true);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
RenderViewports(true, false);
|
|
|
|
|
|
|
|
for (int vp = 0; vp < viewports[m_nViewportMode].n; vp++)
|
|
|
|
{
|
|
|
|
int x = (int)(viewports[m_nViewportMode].dim[vp][0] * ((float)m_nViewX));
|
|
|
|
int y = (int)(viewports[m_nViewportMode].dim[vp][1] * ((float)m_nViewY));
|
|
|
|
int w = (int)(viewports[m_nViewportMode].dim[vp][2] * ((float)m_nViewX));
|
|
|
|
int h = (int)(viewports[m_nViewportMode].dim[vp][3] * ((float)m_nViewY));
|
|
|
|
|
|
|
|
float ratio = (float)w/h;
|
|
|
|
glViewport(x, y, w, h);
|
|
|
|
|
|
|
|
// Disable lighting.
|
|
|
|
if ((m_nSnap & LC_DRAW_AXIS) || (m_nSnap & LC_DRAW_GRID))
|
|
|
|
{
|
|
|
|
if ((bShaded) && (m_nDetail & LC_DET_LIGHTING))
|
|
|
|
glDisable(GL_LIGHTING);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (m_nSnap & LC_DRAW_AXIS)
|
|
|
|
{
|
|
|
|
Matrix Mats[3];
|
|
|
|
Mats[0].CreateLookat(m_pViewCameras[vp]->GetEyePos(), m_pViewCameras[vp]->GetTargetPos(), m_pViewCameras[vp]->GetUpVec());
|
|
|
|
Mats[0].SetTranslation(0, 0, 0);
|
|
|
|
|
|
|
|
float m1[] = { 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 };
|
|
|
|
float m2[] = { 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1 };
|
|
|
|
Mats[1].Multiply(Mats[0], Matrix(m1));
|
|
|
|
Mats[2].Multiply(Mats[0], Matrix(m2));
|
|
|
|
|
|
|
|
float pts[3][3] = { { 20, 0, 0 }, { 0, 20, 0 }, { 0, 0, 20 } };
|
|
|
|
Mats[0].TransformPoints(&pts[0][0], 3);
|
|
|
|
|
|
|
|
glMatrixMode(GL_PROJECTION);
|
|
|
|
glLoadIdentity();
|
|
|
|
glOrtho(0, w, 0, h, -50, 50);
|
|
|
|
glMatrixMode(GL_MODELVIEW);
|
|
|
|
glLoadIdentity();
|
|
|
|
glTranslatef(25.375f, 25.375f, 0.0f);
|
|
|
|
|
|
|
|
// Draw the arrows.
|
|
|
|
for (int i = 0; i < 3; i++)
|
|
|
|
{
|
|
|
|
switch (i)
|
|
|
|
{
|
|
|
|
case 0:
|
|
|
|
glColor3f(0.8f, 0.0f, 0.0f);
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
glColor3f(0.0f, 0.8f, 0.0f);
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
glColor3f(0.0f, 0.0f, 0.8f);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
glBegin(GL_LINES);
|
|
|
|
glVertex3f(pts[i][0], pts[i][1], pts[i][2]);
|
|
|
|
glVertex3f(0, 0, 0);
|
|
|
|
glEnd();
|
|
|
|
|
|
|
|
glBegin(GL_TRIANGLE_FAN);
|
|
|
|
glVertex3f(pts[i][0], pts[i][1], pts[i][2]);
|
|
|
|
for (int j = 0; j < 9; j++)
|
|
|
|
{
|
|
|
|
float pt[3] = { 12.0f, cosf(LC_2PI * j / 8) * 3.0f, sinf(LC_2PI * j / 8) * 3.0f };
|
|
|
|
Mats[i].TransformPoints(pt, 1);
|
|
|
|
glVertex3f(pt[0], pt[1], pt[2]);
|
|
|
|
}
|
|
|
|
glEnd();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Draw the text.
|
|
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
|
|
|
|
m_pScreenFont->MakeCurrent();
|
|
|
|
glEnable(GL_TEXTURE_2D);
|
|
|
|
glEnable(GL_ALPHA_TEST);
|
|
|
|
|
|
|
|
glBegin(GL_QUADS);
|
|
|
|
glColor3f(0, 0, 0);
|
|
|
|
m_pScreenFont->PrintText(pts[0][0], pts[0][1], 40.0f, "X");
|
|
|
|
m_pScreenFont->PrintText(pts[1][0], pts[1][1], 40.0f, "Y");
|
|
|
|
m_pScreenFont->PrintText(pts[2][0], pts[2][1], 40.0f, "Z");
|
|
|
|
glEnd();
|
|
|
|
|
|
|
|
glDisable(GL_TEXTURE_2D);
|
|
|
|
glDisable(GL_ALPHA_TEST);
|
|
|
|
}
|
|
|
|
|
|
|
|
m_pViewCameras[vp]->LoadProjection(ratio);
|
|
|
|
|
|
|
|
if ((m_nSnap & LC_DRAW_AXIS) || (m_nSnap & LC_DRAW_GRID))
|
|
|
|
{
|
|
|
|
glColor3f(1.0f - m_fBackground[0], 1.0f - m_fBackground[1], 1.0f - m_fBackground[2]);
|
|
|
|
|
|
|
|
if (m_nSnap & LC_DRAW_GRID)
|
|
|
|
glCallList (m_nGridList);
|
|
|
|
|
|
|
|
if ((bShaded) && (m_nDetail & LC_DET_LIGHTING))
|
|
|
|
glEnable(GL_LIGHTING);
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((m_nDetail & LC_DET_LIGHTING) != 0)
|
|
|
|
{
|
|
|
|
int index = 0;
|
|
|
|
Light *pLight;
|
|
|
|
|
|
|
|
for (pLight = m_pLights; pLight; pLight = pLight->m_pNext, index++)
|
|
|
|
pLight->Setup (index);
|
|
|
|
}
|
|
|
|
|
|
|
|
// glDisable (GL_COLOR_MATERIAL);
|
|
|
|
/*
|
|
|
|
{
|
|
|
|
for (int i = -100; i < 100; i+=5)
|
|
|
|
{
|
|
|
|
glBegin (GL_QUAD_STRIP);
|
|
|
|
glNormal3f (0,0,1);
|
|
|
|
for (int j = -100; j < 100; j+=5)
|
|
|
|
{
|
|
|
|
glVertex3f ((float)i/10, (float)j/10,0);
|
|
|
|
glVertex3f ((float)(i+5)/10, (float)j/10,0);
|
|
|
|
}
|
|
|
|
glEnd();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
*/
|
|
|
|
/*
|
|
|
|
{
|
|
|
|
LC_RENDER_INFO info;
|
|
|
|
info.lighting = (m_nDetail & LC_DET_LIGHTING) != 0;
|
|
|
|
info.edges = (m_nDetail & LC_DET_BRICKEDGES) != 0;
|
|
|
|
info.fLineWidth = m_fLineWidth;
|
|
|
|
|
|
|
|
info.lastcolor = 255;
|
|
|
|
info.transparent = false;
|
|
|
|
|
|
|
|
|
|
|
|
float pos[] = { 0,0,0 };
|
|
|
|
Curve curve (NULL, pos, 0);
|
|
|
|
curve.Render (&info);
|
|
|
|
}
|
|
|
|
*/
|
|
|
|
if (bShaded)
|
|
|
|
{
|
|
|
|
if (m_nScene & LC_SCENE_FLOOR)
|
|
|
|
m_pTerrain->Render(m_pViewCameras[vp], ratio);
|
|
|
|
|
|
|
|
unsigned char nLastColor = 255;
|
|
|
|
bool bTrans = false;
|
|
|
|
bool bSel = false;
|
|
|
|
bool bCull = false;
|
|
|
|
Piece* pPiece;
|
|
|
|
|
|
|
|
LC_BSPNODE tree;
|
|
|
|
tree.front = tree.back = NULL;
|
|
|
|
Piece* pList = NULL;
|
|
|
|
|
|
|
|
// Draw opaque pieces first
|
|
|
|
for (pPiece = m_pPieces; pPiece; pPiece = pPiece->m_pNext)
|
|
|
|
{
|
|
|
|
// if (m_nDetail & LC_DET_BACKGROUND)
|
|
|
|
// {
|
|
|
|
// SystemPumpMessages();
|
|
|
|
// if (m_bStopRender)
|
|
|
|
// return;
|
|
|
|
// }
|
|
|
|
|
|
|
|
if (pPiece->IsVisible(m_bAnimation ? m_nCurFrame : m_nCurStep, m_bAnimation))
|
|
|
|
{
|
|
|
|
if (!pPiece->IsTransparent())
|
|
|
|
{
|
|
|
|
if (pPiece->IsSelected())
|
|
|
|
{
|
|
|
|
if (!bSel)
|
|
|
|
{
|
|
|
|
bSel = true;
|
|
|
|
glLineWidth (2*m_fLineWidth);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (bSel)
|
|
|
|
{
|
|
|
|
bSel = false;
|
|
|
|
glLineWidth(m_fLineWidth);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
if (pPiece->m_pInfo->m_nConnectionCount == 1)
|
|
|
|
{
|
|
|
|
if (bCull)
|
|
|
|
{
|
|
|
|
bCull = false;
|
|
|
|
glDisable(GL_CULL_FACE);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (!bCull)
|
|
|
|
{
|
|
|
|
bCull = true;
|
|
|
|
glEnable(GL_CULL_FACE);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
*/
|
|
|
|
pPiece->Render((m_nDetail & LC_DET_LIGHTING) != 0, (m_nDetail & LC_DET_BRICKEDGES) != 0, &nLastColor, &bTrans);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
pPiece->m_pLink = pList;
|
|
|
|
pList = pPiece;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (pList)
|
|
|
|
{
|
|
|
|
float eye[3];
|
|
|
|
m_pViewCameras[vp]->GetEyePos (eye);
|
|
|
|
BuildBSP(&tree, pList);
|
|
|
|
RenderBSP(&tree, eye, &bSel,
|
|
|
|
(m_nDetail & LC_DET_LIGHTING) != 0, (m_nDetail & LC_DET_BRICKEDGES) != 0, &nLastColor, &bTrans);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
// Draw transparent pieces
|
|
|
|
for (pPiece = m_pPieces; pPiece; pPiece = pPiece->m_pNext)
|
|
|
|
{
|
|
|
|
// MSG msg;
|
|
|
|
// while(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
|
|
|
|
// {
|
|
|
|
// TranslateMessage(&msg);
|
|
|
|
// DispatchMessage(&msg);
|
|
|
|
// if (m_bStopRender)
|
|
|
|
// return;
|
|
|
|
// }
|
|
|
|
|
|
|
|
if ((pPiece->IsVisible(m_bAnimation ? m_nCurFrame : m_nCurStep, m_bAnimation)) &&
|
|
|
|
(pPiece->IsTransparent()))
|
|
|
|
{
|
|
|
|
if (pPiece->IsSelected())
|
|
|
|
{
|
|
|
|
if (!bSel)
|
|
|
|
{
|
|
|
|
bSel = true;
|
|
|
|
glLineWidth (2*m_fLineWidth);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (bSel)
|
|
|
|
{
|
|
|
|
bSel = false;
|
|
|
|
glLineWidth(m_fLineWidth);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
if (pPiece->m_pInfo->m_nConnectionCount == 1)
|
|
|
|
{
|
|
|
|
if (bCull)
|
|
|
|
{
|
|
|
|
bCull = FALSE;
|
|
|
|
glDisable(GL_CULL_FACE);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (!bCull)
|
|
|
|
{
|
|
|
|
bCull = TRUE;
|
|
|
|
glEnable(GL_CULL_FACE);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
*/
|
|
|
|
pPiece->Render((m_nDetail & LC_DET_LIGHTING) != 0, (m_nDetail & LC_DET_BRICKEDGES) != 0, &nLastColor, &bTrans);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
if (bTrans)
|
|
|
|
{
|
|
|
|
glDepthMask(GL_TRUE);
|
|
|
|
glDisable(GL_BLEND);
|
|
|
|
}
|
|
|
|
if (bSel)
|
|
|
|
glLineWidth(m_fLineWidth);
|
|
|
|
if (bCull)
|
|
|
|
glDisable(GL_CULL_FACE);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// glEnable (GL_CULL_FACE);
|
|
|
|
// glShadeModel (GL_FLAT);
|
|
|
|
// glDisable (GL_LIGHTING);
|
2011-09-20 01:03:28 +02:00
|
|
|
|
|
|
|
// Wireframe
|
|
|
|
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
|
|
|
|
RenderBoxes(true);
|
|
|
|
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
|
2011-09-07 23:06:51 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef LC_DEBUG
|
|
|
|
RenderDebugPrimitives();
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// Draw cameras & lights
|
|
|
|
if (bDrawViewports)
|
|
|
|
{
|
|
|
|
if (m_nCurAction == LC_ACTION_INSERT)
|
|
|
|
{
|
|
|
|
Vector3 Pos;
|
|
|
|
Vector4 Rot;
|
|
|
|
GetPieceInsertPosition(m_nDownX, m_nDownY, Pos, Rot);
|
|
|
|
|
|
|
|
glPushMatrix();
|
|
|
|
glTranslatef(Pos[0], Pos[1], Pos[2]);
|
|
|
|
glRotatef(Rot[3], Rot[0], Rot[1], Rot[2]);
|
|
|
|
glLineWidth(2*m_fLineWidth);
|
|
|
|
m_pCurPiece->RenderPiece(m_nCurColor);
|
|
|
|
glLineWidth(m_fLineWidth);
|
|
|
|
glPopMatrix();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (m_nDetail & LC_DET_LIGHTING)
|
|
|
|
{
|
|
|
|
glDisable (GL_LIGHTING);
|
|
|
|
int index = 0;
|
|
|
|
Light *pLight;
|
|
|
|
|
|
|
|
for (pLight = m_pLights; pLight; pLight = pLight->m_pNext, index++)
|
|
|
|
glDisable ((GLenum)(GL_LIGHT0+index));
|
|
|
|
}
|
|
|
|
|
|
|
|
Camera* pCamera;
|
|
|
|
Light* pLight;
|
|
|
|
|
|
|
|
for (pCamera = m_pCameras; pCamera; pCamera = pCamera->m_pNext)
|
|
|
|
{
|
|
|
|
if ((pCamera == m_pViewCameras[vp]) || !pCamera->IsVisible())
|
|
|
|
continue;
|
|
|
|
pCamera->Render(m_fLineWidth);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (pLight = m_pLights; pLight; pLight = pLight->m_pNext)
|
|
|
|
if (pLight->IsVisible ())
|
|
|
|
pLight->Render(m_fLineWidth);
|
|
|
|
|
|
|
|
if (m_nDetail & LC_DET_LIGHTING)
|
|
|
|
glEnable (GL_LIGHTING);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Draw the selection rectangle.
|
|
|
|
if ((m_nCurAction == LC_ACTION_SELECT) && (m_nTracking == LC_TRACK_LEFT))
|
|
|
|
{
|
|
|
|
int x, y, w, h;
|
|
|
|
|
|
|
|
x = (int)(viewports[m_nViewportMode].dim[m_nActiveViewport][0] * (float)m_nViewX);
|
|
|
|
y = (int)(viewports[m_nViewportMode].dim[m_nActiveViewport][1] * (float)m_nViewY);
|
|
|
|
w = (int)(viewports[m_nViewportMode].dim[m_nActiveViewport][2] * (float)m_nViewX);
|
|
|
|
h = (int)(viewports[m_nViewportMode].dim[m_nActiveViewport][3] * (float)m_nViewY);
|
|
|
|
|
|
|
|
glViewport(x, y, w, h);
|
|
|
|
|
|
|
|
glMatrixMode(GL_PROJECTION);
|
|
|
|
glLoadIdentity();
|
|
|
|
glOrtho(0, w, 0, h, -1, 1);
|
|
|
|
glMatrixMode(GL_MODELVIEW);
|
|
|
|
glLoadIdentity();
|
|
|
|
glTranslatef(0.375, 0.375, 0.0);
|
|
|
|
|
|
|
|
glDisable(GL_DEPTH_TEST);
|
|
|
|
glEnable(GL_LINE_STIPPLE);
|
|
|
|
glLineStipple(5, 0x5555);
|
|
|
|
glColor3f(0, 0, 0);
|
|
|
|
|
|
|
|
float pt1x = (float)(m_nDownX - x);
|
|
|
|
float pt1y = (float)(m_nDownY - y);
|
|
|
|
float pt2x = m_fTrack[0] - x;
|
|
|
|
float pt2y = m_fTrack[1] - y;
|
|
|
|
|
|
|
|
glBegin(GL_LINES);
|
|
|
|
glVertex2f(pt1x, pt1y);
|
|
|
|
glVertex2f(pt2x, pt1y);
|
|
|
|
glVertex2f(pt2x, pt1y);
|
|
|
|
glVertex2f(pt2x, pt2y);
|
|
|
|
glVertex2f(pt2x, pt2y);
|
|
|
|
glVertex2f(pt1x, pt2y);
|
|
|
|
glVertex2f(pt1x, pt2y);
|
|
|
|
glVertex2f(pt1x, pt1y);
|
|
|
|
glEnd();
|
|
|
|
|
|
|
|
glDisable(GL_LINE_STIPPLE);
|
|
|
|
glEnable(GL_DEPTH_TEST);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (bDrawViewports && m_OverlayActive)
|
|
|
|
RenderOverlays(vp);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Project::RenderOverlays(int Viewport)
|
|
|
|
{
|
|
|
|
const float OverlayScale = m_OverlayScale[Viewport];
|
|
|
|
|
|
|
|
if (m_nCurAction == LC_ACTION_MOVE)
|
|
|
|
{
|
|
|
|
const float OverlayMovePlaneSize = 0.5f;
|
|
|
|
const float OverlayMoveArrowSize = 1.5f;
|
|
|
|
const float OverlayMoveArrowCapSize = 0.9f;
|
|
|
|
const float OverlayMoveArrowCapRadius = 0.1f;
|
|
|
|
|
|
|
|
glDisable(GL_DEPTH_TEST);
|
|
|
|
|
|
|
|
// Find the rotation from the focused piece if relative snap is enabled.
|
|
|
|
Object* Focus = NULL;
|
|
|
|
float Rot[4];
|
|
|
|
|
|
|
|
if ((m_nSnap & LC_DRAW_GLOBAL_SNAP) == 0)
|
|
|
|
{
|
|
|
|
Focus = GetFocusObject();
|
|
|
|
|
|
|
|
if ((Focus != NULL) && Focus->IsPiece())
|
|
|
|
((Piece*)Focus)->GetRotation(Rot);
|
|
|
|
else
|
|
|
|
Focus = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Draw a quad if we're moving on a plane.
|
|
|
|
if ((m_OverlayMode == LC_OVERLAY_XY) || (m_OverlayMode == LC_OVERLAY_XZ) || (m_OverlayMode == LC_OVERLAY_YZ))
|
|
|
|
{
|
|
|
|
glPushMatrix();
|
|
|
|
glTranslatef(m_OverlayCenter[0], m_OverlayCenter[1], m_OverlayCenter[2]);
|
|
|
|
|
|
|
|
if (Focus)
|
|
|
|
glRotatef(Rot[3], Rot[0], Rot[1], Rot[2]);
|
|
|
|
|
|
|
|
if (m_OverlayMode == LC_OVERLAY_XZ)
|
|
|
|
glRotatef(90.0f, 0.0f, 0.0f, -1.0f);
|
|
|
|
else if (m_OverlayMode == LC_OVERLAY_XY)
|
|
|
|
glRotatef(90.0f, 0.0f, 1.0f, 0.0f);
|
|
|
|
|
|
|
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
|
|
|
glEnable(GL_BLEND);
|
|
|
|
|
|
|
|
glBegin(GL_QUADS);
|
|
|
|
glColor4f(0.8f, 0.8f, 0.0f, 0.3f);
|
|
|
|
glVertex3f(0.0f, 0.0f, 0.0f);
|
|
|
|
glVertex3f(0.0f, OverlayScale * OverlayMovePlaneSize, 0.0f);
|
|
|
|
glVertex3f(0.0f, OverlayScale * OverlayMovePlaneSize, OverlayScale * OverlayMovePlaneSize);
|
|
|
|
glVertex3f(0.0f, 0.0f, OverlayScale * OverlayMovePlaneSize);
|
|
|
|
glEnd();
|
|
|
|
|
|
|
|
glDisable(GL_BLEND);
|
|
|
|
|
|
|
|
glPopMatrix();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Draw the arrows.
|
|
|
|
for (int i = 0; i < 3; i++)
|
|
|
|
{
|
|
|
|
switch (i)
|
|
|
|
{
|
|
|
|
case 0:
|
|
|
|
if ((m_OverlayMode == LC_OVERLAY_X) || (m_OverlayMode == LC_OVERLAY_XY) || (m_OverlayMode == LC_OVERLAY_XZ))
|
|
|
|
glColor3f(0.8f, 0.8f, 0.0f);
|
|
|
|
else
|
|
|
|
glColor3f(0.8f, 0.0f, 0.0f);
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
if ((m_OverlayMode == LC_OVERLAY_Y) || (m_OverlayMode == LC_OVERLAY_XY) || (m_OverlayMode == LC_OVERLAY_YZ))
|
|
|
|
glColor3f(0.8f, 0.8f, 0.0f);
|
|
|
|
else
|
|
|
|
glColor3f(0.0f, 0.8f, 0.0f);
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
if ((m_OverlayMode == LC_OVERLAY_Z) || (m_OverlayMode == LC_OVERLAY_XZ) || (m_OverlayMode == LC_OVERLAY_YZ))
|
|
|
|
glColor3f(0.8f, 0.8f, 0.0f);
|
|
|
|
else
|
|
|
|
glColor3f(0.0f, 0.0f, 0.8f);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
glPushMatrix();
|
|
|
|
glTranslatef(m_OverlayCenter[0], m_OverlayCenter[1], m_OverlayCenter[2]);
|
|
|
|
|
|
|
|
if (Focus)
|
|
|
|
glRotatef(Rot[3], Rot[0], Rot[1], Rot[2]);
|
|
|
|
|
|
|
|
if (i == 1)
|
|
|
|
glRotatef(90.0f, 0.0f, 0.0f, 1.0f);
|
|
|
|
else if (i == 2)
|
|
|
|
glRotatef(90.0f, 0.0f, -1.0f, 0.0f);
|
|
|
|
|
|
|
|
glBegin(GL_LINES);
|
|
|
|
glVertex3f(0.0f, 0.0f, 0.0f);
|
|
|
|
glVertex3f(OverlayScale * OverlayMoveArrowSize, 0.0f, 0.0f);
|
|
|
|
glEnd();
|
|
|
|
|
|
|
|
glBegin(GL_TRIANGLE_FAN);
|
|
|
|
glVertex3f(OverlayScale * OverlayMoveArrowSize, 0.0f, 0.0f);
|
|
|
|
for (int j = 0; j < 9; j++)
|
|
|
|
{
|
|
|
|
float y = cosf(LC_2PI * j / 8) * OverlayMoveArrowCapRadius * OverlayScale;
|
|
|
|
float z = sinf(LC_2PI * j / 8) * OverlayMoveArrowCapRadius * OverlayScale;
|
|
|
|
glVertex3f(OverlayScale * OverlayMoveArrowCapSize, y, z);
|
|
|
|
}
|
|
|
|
glEnd();
|
|
|
|
|
|
|
|
glPopMatrix();
|
|
|
|
}
|
|
|
|
|
|
|
|
glEnable(GL_DEPTH_TEST);
|
|
|
|
}
|
|
|
|
else if (m_nCurAction == LC_ACTION_ROTATE)
|
|
|
|
{
|
|
|
|
const float OverlayRotateRadius = 2.0f;
|
|
|
|
|
|
|
|
glDisable(GL_DEPTH_TEST);
|
|
|
|
|
|
|
|
Camera* Cam = m_pViewCameras[Viewport];
|
|
|
|
Matrix44 Mat;
|
|
|
|
int j;
|
|
|
|
|
|
|
|
// Find the rotation from the focused piece if relative snap is enabled.
|
|
|
|
Object* Focus = NULL;
|
|
|
|
float Rot[4];
|
|
|
|
|
|
|
|
if ((m_nSnap & LC_DRAW_GLOBAL_SNAP) == 0)
|
|
|
|
{
|
|
|
|
Focus = GetFocusObject();
|
|
|
|
|
|
|
|
if ((Focus != NULL) && Focus->IsPiece())
|
|
|
|
((Piece*)Focus)->GetRotation(Rot);
|
|
|
|
else
|
|
|
|
Focus = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Draw a disc showing the rotation amount.
|
|
|
|
if (m_MouseTotalDelta.LengthSquared() != 0.0f && (m_nTracking != LC_TRACK_NONE))
|
|
|
|
{
|
|
|
|
Vector4 Rotation;
|
|
|
|
float Angle, Step;
|
|
|
|
|
|
|
|
switch (m_OverlayMode)
|
|
|
|
{
|
|
|
|
case LC_OVERLAY_X:
|
|
|
|
glColor4f(0.8f, 0.0f, 0.0f, 0.3f);
|
|
|
|
Angle = m_MouseTotalDelta[0];
|
|
|
|
Rotation = Vector4(0.0f, 0.0f, 0.0f, 0.0f);
|
|
|
|
break;
|
|
|
|
case LC_OVERLAY_Y:
|
|
|
|
glColor4f(0.0f, 0.8f, 0.0f, 0.3f);
|
|
|
|
Angle = m_MouseTotalDelta[1];
|
|
|
|
Rotation = Vector4(90.0f, 0.0f, 0.0f, 1.0f);
|
|
|
|
break;
|
|
|
|
case LC_OVERLAY_Z:
|
|
|
|
glColor4f(0.0f, 0.0f, 0.8f, 0.3f);
|
|
|
|
Angle = m_MouseTotalDelta[2];
|
|
|
|
Rotation = Vector4(90.0f, 0.0f, -1.0f, 0.0f);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
Angle = 0.0f;
|
|
|
|
break;
|
|
|
|
};
|
|
|
|
|
|
|
|
if (Angle > 0.0f)
|
|
|
|
{
|
|
|
|
Step = 360.0f / 32;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
Angle = -Angle;
|
|
|
|
Step = -360.0f / 32;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (fabsf(Angle) >= fabsf(Step))
|
|
|
|
{
|
|
|
|
glPushMatrix();
|
|
|
|
glTranslatef(m_OverlayCenter[0], m_OverlayCenter[1], m_OverlayCenter[2]);
|
|
|
|
|
|
|
|
if (Focus)
|
|
|
|
glRotatef(Rot[3], Rot[0], Rot[1], Rot[2]);
|
|
|
|
|
|
|
|
glRotatef(Rotation[0], Rotation[1], Rotation[2], Rotation[3]);
|
|
|
|
|
|
|
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
|
|
|
glEnable(GL_BLEND);
|
|
|
|
|
|
|
|
glBegin(GL_TRIANGLE_FAN);
|
|
|
|
|
|
|
|
glVertex3f(0.0f, 0.0f, 0.0f);
|
|
|
|
|
|
|
|
float StartAngle;
|
|
|
|
int i = 0;
|
|
|
|
|
|
|
|
if (Step < 0)
|
|
|
|
StartAngle = -Angle;
|
|
|
|
else
|
|
|
|
StartAngle = Angle;
|
|
|
|
|
|
|
|
do
|
|
|
|
{
|
|
|
|
float x = cosf((Step * i - StartAngle) * DTOR) * OverlayRotateRadius * OverlayScale;
|
|
|
|
float y = sinf((Step * i - StartAngle) * DTOR) * OverlayRotateRadius * OverlayScale;
|
|
|
|
|
|
|
|
glVertex3f(0.0f, x, y);
|
|
|
|
|
|
|
|
i++;
|
|
|
|
if (Step > 0)
|
|
|
|
Angle -= Step;
|
|
|
|
else
|
|
|
|
Angle += Step;
|
|
|
|
|
|
|
|
} while (Angle >= 0.0f);
|
|
|
|
|
|
|
|
glEnd();
|
|
|
|
|
|
|
|
glDisable(GL_BLEND);
|
|
|
|
|
|
|
|
glPopMatrix();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Mat.CreateLookAt(Cam->GetEyePosition(), Cam->GetTargetPosition(), Cam->GetUpVector());
|
|
|
|
Mat.Transpose3();
|
|
|
|
Mat.SetTranslation(m_OverlayCenter);
|
|
|
|
|
|
|
|
// Draw the circles.
|
|
|
|
glBegin(GL_LINE_LOOP);
|
|
|
|
glColor3f(0.1f, 0.1f, 0.1f);
|
|
|
|
|
|
|
|
for (j = 0; j < 32; j++)
|
|
|
|
{
|
|
|
|
Vector3 Pt;
|
|
|
|
|
|
|
|
Pt[0] = cosf(LC_2PI * j / 32) * OverlayRotateRadius * OverlayScale;
|
|
|
|
Pt[1] = sinf(LC_2PI * j / 32) * OverlayRotateRadius * OverlayScale;
|
|
|
|
Pt[2] = 0.0f;
|
|
|
|
|
|
|
|
Pt = Mul31(Pt, Mat);
|
|
|
|
|
|
|
|
glVertex3f(Pt[0], Pt[1], Pt[2]);
|
|
|
|
}
|
|
|
|
|
|
|
|
glEnd();
|
|
|
|
|
|
|
|
Vector3 ViewDir = Cam->GetTargetPosition() - Cam->GetEyePosition();
|
|
|
|
ViewDir.Normalize();
|
|
|
|
|
|
|
|
// Transform ViewDir to local space.
|
|
|
|
if (Focus)
|
|
|
|
{
|
|
|
|
Matrix33 RotMat;
|
|
|
|
RotMat.CreateFromAxisAngle(Vector3(Rot[0], Rot[1], Rot[2]), -Rot[3] * LC_DTOR);
|
|
|
|
|
|
|
|
ViewDir = Mul(ViewDir, RotMat);
|
|
|
|
}
|
|
|
|
|
|
|
|
glTranslatef(m_OverlayCenter[0], m_OverlayCenter[1], m_OverlayCenter[2]);
|
|
|
|
|
|
|
|
if (Focus)
|
|
|
|
glRotatef(Rot[3], Rot[0], Rot[1], Rot[2]);
|
|
|
|
|
|
|
|
// Draw each axis circle.
|
|
|
|
for (int i = 0; i < 3; i++)
|
|
|
|
{
|
|
|
|
if (m_OverlayMode == LC_OVERLAY_X + i)
|
|
|
|
{
|
|
|
|
glColor3f(0.8f, 0.8f, 0.0f);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
switch (i)
|
|
|
|
{
|
|
|
|
case 0:
|
|
|
|
glColor3f(0.8f, 0.0f, 0.0f);
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
glColor3f(0.0f, 0.8f, 0.0f);
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
glColor3f(0.0f, 0.0f, 0.8f);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
glBegin(GL_LINES);
|
|
|
|
|
|
|
|
for (int j = 0; j < 32; j++)
|
|
|
|
{
|
|
|
|
Vector3 v1, v2;
|
|
|
|
|
|
|
|
switch (i)
|
|
|
|
{
|
|
|
|
case 0:
|
|
|
|
v1 = Vector3(0.0f, cosf(LC_2PI * j / 32), sinf(LC_2PI * j / 32));
|
|
|
|
v2 = Vector3(0.0f, cosf(LC_2PI * (j + 1) / 32), sinf(LC_2PI * (j + 1) / 32));
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 1:
|
|
|
|
v1 = Vector3(cosf(LC_2PI * j / 32), 0.0f, sinf(LC_2PI * j / 32));
|
|
|
|
v2 = Vector3(cosf(LC_2PI * (j + 1) / 32), 0.0f, sinf(LC_2PI * (j + 1) / 32));
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 2:
|
|
|
|
v1 = Vector3(cosf(LC_2PI * j / 32), sinf(LC_2PI * j / 32), 0.0f);
|
|
|
|
v2 = Vector3(cosf(LC_2PI * (j + 1) / 32), sinf(LC_2PI * (j + 1) / 32), 0.0f);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Dot3(ViewDir, v1+v2) <= 0.0f)
|
|
|
|
{
|
|
|
|
Vector3 Pt1 = v1 * OverlayRotateRadius * OverlayScale;
|
|
|
|
Vector3 Pt2 = v2 * OverlayRotateRadius * OverlayScale;
|
|
|
|
|
|
|
|
glVertex3f(Pt1[0], Pt1[1], Pt1[2]);
|
|
|
|
glVertex3f(Pt2[0], Pt2[1], Pt2[2]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
glEnd();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Draw tangent vector.
|
|
|
|
if (m_nTracking != LC_TRACK_NONE)
|
|
|
|
{
|
|
|
|
if ((m_OverlayMode == LC_OVERLAY_X) || (m_OverlayMode == LC_OVERLAY_Y) || (m_OverlayMode == LC_OVERLAY_Z))
|
|
|
|
{
|
|
|
|
Vector3 Tangent, Normal = m_OverlayTrackStart - m_OverlayCenter;
|
|
|
|
Normal.Normalize();
|
|
|
|
float Angle;
|
|
|
|
|
|
|
|
switch (m_OverlayMode)
|
|
|
|
{
|
|
|
|
case LC_OVERLAY_X:
|
|
|
|
Angle = m_MouseTotalDelta[0];
|
|
|
|
Tangent = Vector3(0.0f, -Normal[2], Normal[1]);
|
|
|
|
break;
|
|
|
|
case LC_OVERLAY_Y:
|
|
|
|
Angle = m_MouseTotalDelta[1];
|
|
|
|
Tangent = Vector3(Normal[2], 0.0f, -Normal[0]);
|
|
|
|
break;
|
|
|
|
case LC_OVERLAY_Z:
|
|
|
|
Angle = m_MouseTotalDelta[2];
|
|
|
|
Tangent = Vector3(-Normal[1], Normal[0], 0.0f);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Angle < 0.0f)
|
|
|
|
{
|
|
|
|
Tangent = -Tangent;
|
|
|
|
Angle = -Angle;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Draw tangent arrow.
|
|
|
|
if (Angle > 0.0f)
|
|
|
|
{
|
|
|
|
const float OverlayRotateArrowSize = 1.5f;
|
|
|
|
const float OverlayRotateArrowCapSize = 0.25f;
|
|
|
|
|
|
|
|
Vector3 Pt = Normal * OverlayScale * OverlayRotateRadius;
|
|
|
|
Vector3 Tip = Pt + Tangent * OverlayScale * OverlayRotateArrowSize;
|
|
|
|
Vector3 Arrow;
|
|
|
|
Matrix33 Rot;
|
|
|
|
|
|
|
|
glBegin(GL_LINES);
|
|
|
|
glColor3f(0.8f, 0.8f, 0.0f);
|
|
|
|
|
|
|
|
glVertex3f(Pt[0], Pt[1], Pt[2]);
|
|
|
|
glVertex3f(Tip[0], Tip[1], Tip[2]);
|
|
|
|
|
|
|
|
Rot.CreateFromAxisAngle(Normal, LC_PI * 0.15f);
|
|
|
|
Arrow = Mul(Tangent, Rot) * OverlayRotateArrowCapSize;
|
|
|
|
|
|
|
|
glVertex3f(Tip[0], Tip[1], Tip[2]);
|
|
|
|
glVertex3f(Tip[0] - Arrow[0], Tip[1] - Arrow[1], Tip[2] - Arrow[2]);
|
|
|
|
|
|
|
|
Rot.CreateFromAxisAngle(Normal, -LC_PI * 0.15f);
|
|
|
|
Arrow = Mul(Tangent, Rot) * OverlayRotateArrowCapSize;
|
|
|
|
|
|
|
|
glVertex3f(Tip[0], Tip[1], Tip[2]);
|
|
|
|
glVertex3f(Tip[0] - Arrow[0], Tip[1] - Arrow[1], Tip[2] - Arrow[2]);
|
|
|
|
|
|
|
|
glEnd();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Draw text.
|
|
|
|
if (Viewport == m_nActiveViewport)
|
|
|
|
{
|
|
|
|
GLdouble ScreenX, ScreenY, ScreenZ;
|
|
|
|
GLdouble ModelMatrix[16], ProjMatrix[16];
|
|
|
|
GLint Vp[4];
|
|
|
|
|
|
|
|
glGetDoublev(GL_MODELVIEW_MATRIX, ModelMatrix);
|
|
|
|
glGetDoublev(GL_PROJECTION_MATRIX, ProjMatrix);
|
|
|
|
glGetIntegerv(GL_VIEWPORT, Vp);
|
|
|
|
|
|
|
|
gluProject(0, 0, 0, ModelMatrix, ProjMatrix, Vp, &ScreenX, &ScreenY, &ScreenZ);
|
|
|
|
|
|
|
|
glMatrixMode(GL_PROJECTION);
|
|
|
|
glPushMatrix();
|
|
|
|
glLoadIdentity();
|
|
|
|
glOrtho(0, Vp[2], 0, Vp[3], -1, 1);
|
|
|
|
glMatrixMode(GL_MODELVIEW);
|
|
|
|
glPushMatrix();
|
|
|
|
glLoadIdentity();
|
|
|
|
glTranslatef(0.375, 0.375, 0.0);
|
|
|
|
|
|
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
|
|
|
|
m_pScreenFont->MakeCurrent();
|
|
|
|
glEnable(GL_TEXTURE_2D);
|
|
|
|
glEnable(GL_ALPHA_TEST);
|
|
|
|
|
|
|
|
char buf[32];
|
|
|
|
sprintf(buf, "[%.2f]", Angle);
|
|
|
|
|
|
|
|
int cx, cy;
|
|
|
|
m_pScreenFont->GetStringDimensions(&cx, &cy, buf);
|
|
|
|
|
|
|
|
glBegin(GL_QUADS);
|
|
|
|
glColor3f(0.8f, 0.8f, 0.0f);
|
|
|
|
m_pScreenFont->PrintText((float)ScreenX - Vp[0] - (cx / 2), (float)ScreenY - Vp[1] + (cy / 2), 0.0f, buf);
|
|
|
|
glEnd();
|
|
|
|
|
|
|
|
glDisable(GL_TEXTURE_2D);
|
|
|
|
glDisable(GL_ALPHA_TEST);
|
|
|
|
|
|
|
|
glMatrixMode(GL_PROJECTION);
|
|
|
|
glPopMatrix();
|
|
|
|
glMatrixMode(GL_MODELVIEW);
|
|
|
|
glPopMatrix();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
glEnable(GL_DEPTH_TEST);
|
|
|
|
}
|
|
|
|
else if (m_nCurAction == LC_ACTION_ROTATE_VIEW)
|
|
|
|
{
|
|
|
|
int x, y, w, h;
|
|
|
|
|
|
|
|
x = (int)(viewports[m_nViewportMode].dim[m_nActiveViewport][0] * (float)m_nViewX);
|
|
|
|
y = (int)(viewports[m_nViewportMode].dim[m_nActiveViewport][1] * (float)m_nViewY);
|
|
|
|
w = (int)(viewports[m_nViewportMode].dim[m_nActiveViewport][2] * (float)m_nViewX);
|
|
|
|
h = (int)(viewports[m_nViewportMode].dim[m_nActiveViewport][3] * (float)m_nViewY);
|
|
|
|
|
|
|
|
glViewport(0, 0, m_nViewX, m_nViewY);
|
|
|
|
glMatrixMode(GL_PROJECTION);
|
|
|
|
glLoadIdentity();
|
|
|
|
glOrtho(0, m_nViewX, 0, m_nViewY, -1, 1);
|
|
|
|
glMatrixMode(GL_MODELVIEW);
|
|
|
|
glLoadIdentity();
|
|
|
|
glTranslatef(0.375f, 0.375f, 0.0f);
|
|
|
|
|
|
|
|
glDisable(GL_DEPTH_TEST);
|
|
|
|
glColor3f(0, 0, 0);
|
|
|
|
|
|
|
|
// Draw circle.
|
|
|
|
glBegin(GL_LINE_LOOP);
|
|
|
|
|
|
|
|
float r = min(w, h) * 0.35f;
|
|
|
|
float cx = x + w / 2.0f;
|
|
|
|
float cy = y + h / 2.0f;
|
|
|
|
|
|
|
|
for (int i = 0; i < 32; i++)
|
|
|
|
{
|
|
|
|
float x = cosf((float)i / 32.0f * (2.0f * LC_PI)) * r + cx;
|
|
|
|
float y = sinf((float)i / 32.0f * (2.0f * LC_PI)) * r + cy;
|
|
|
|
|
|
|
|
glVertex2f(x, y);
|
|
|
|
}
|
|
|
|
|
|
|
|
glEnd();
|
|
|
|
|
|
|
|
const float OverlayCameraSquareSize = max(8.0f, (w+h)/200);
|
|
|
|
|
|
|
|
// Draw squares.
|
|
|
|
glBegin(GL_LINE_LOOP);
|
|
|
|
glVertex2f(cx + OverlayCameraSquareSize, cy + r + OverlayCameraSquareSize);
|
|
|
|
glVertex2f(cx - OverlayCameraSquareSize, cy + r + OverlayCameraSquareSize);
|
|
|
|
glVertex2f(cx - OverlayCameraSquareSize, cy + r - OverlayCameraSquareSize);
|
|
|
|
glVertex2f(cx + OverlayCameraSquareSize, cy + r - OverlayCameraSquareSize);
|
|
|
|
glEnd();
|
|
|
|
|
|
|
|
glBegin(GL_LINE_LOOP);
|
|
|
|
glVertex2f(cx + OverlayCameraSquareSize, cy - r + OverlayCameraSquareSize);
|
|
|
|
glVertex2f(cx - OverlayCameraSquareSize, cy - r + OverlayCameraSquareSize);
|
|
|
|
glVertex2f(cx - OverlayCameraSquareSize, cy - r - OverlayCameraSquareSize);
|
|
|
|
glVertex2f(cx + OverlayCameraSquareSize, cy - r - OverlayCameraSquareSize);
|
|
|
|
glEnd();
|
|
|
|
|
|
|
|
glBegin(GL_LINE_LOOP);
|
|
|
|
glVertex2f(cx + r + OverlayCameraSquareSize, cy + OverlayCameraSquareSize);
|
|
|
|
glVertex2f(cx + r - OverlayCameraSquareSize, cy + OverlayCameraSquareSize);
|
|
|
|
glVertex2f(cx + r - OverlayCameraSquareSize, cy - OverlayCameraSquareSize);
|
|
|
|
glVertex2f(cx + r + OverlayCameraSquareSize, cy - OverlayCameraSquareSize);
|
|
|
|
glEnd();
|
|
|
|
|
|
|
|
glBegin(GL_LINE_LOOP);
|
|
|
|
glVertex2f(cx - r + OverlayCameraSquareSize, cy + OverlayCameraSquareSize);
|
|
|
|
glVertex2f(cx - r - OverlayCameraSquareSize, cy + OverlayCameraSquareSize);
|
|
|
|
glVertex2f(cx - r - OverlayCameraSquareSize, cy - OverlayCameraSquareSize);
|
|
|
|
glVertex2f(cx - r + OverlayCameraSquareSize, cy - OverlayCameraSquareSize);
|
|
|
|
glEnd();
|
|
|
|
|
|
|
|
glEnable(GL_DEPTH_TEST);
|
|
|
|
}
|
|
|
|
else if (m_nCurAction == LC_ACTION_ZOOM_REGION)
|
|
|
|
{
|
|
|
|
int x, y, w, h;
|
|
|
|
|
|
|
|
x = (int)(viewports[m_nViewportMode].dim[m_nActiveViewport][0] * (float)m_nViewX);
|
|
|
|
y = (int)(viewports[m_nViewportMode].dim[m_nActiveViewport][1] * (float)m_nViewY);
|
|
|
|
w = (int)(viewports[m_nViewportMode].dim[m_nActiveViewport][2] * (float)m_nViewX);
|
|
|
|
h = (int)(viewports[m_nViewportMode].dim[m_nActiveViewport][3] * (float)m_nViewY);
|
|
|
|
|
|
|
|
glViewport(0, 0, m_nViewX, m_nViewY);
|
|
|
|
glMatrixMode(GL_PROJECTION);
|
|
|
|
glLoadIdentity();
|
|
|
|
glOrtho(0, m_nViewX, 0, m_nViewY, -1, 1);
|
|
|
|
glMatrixMode(GL_MODELVIEW);
|
|
|
|
glLoadIdentity();
|
|
|
|
glTranslatef(0.375f, 0.375f, 0.0f);
|
|
|
|
|
|
|
|
glDisable(GL_DEPTH_TEST);
|
|
|
|
glEnable(GL_LINE_STIPPLE);
|
|
|
|
glLineStipple(5, 0x5555);
|
|
|
|
glColor3f(0, 0, 0);
|
|
|
|
|
|
|
|
float pt1x = (float)(m_nDownX - x);
|
|
|
|
float pt1y = (float)(m_nDownY - y);
|
|
|
|
float pt2x = m_OverlayTrackStart[0] - x;
|
|
|
|
float pt2y = m_OverlayTrackStart[1] - y;
|
|
|
|
|
|
|
|
glBegin(GL_LINES);
|
|
|
|
glVertex2f(pt1x, pt1y);
|
|
|
|
glVertex2f(pt2x, pt1y);
|
|
|
|
glVertex2f(pt2x, pt1y);
|
|
|
|
glVertex2f(pt2x, pt2y);
|
|
|
|
glVertex2f(pt2x, pt2y);
|
|
|
|
glVertex2f(pt1x, pt2y);
|
|
|
|
glVertex2f(pt1x, pt2y);
|
|
|
|
glVertex2f(pt1x, pt1y);
|
|
|
|
glEnd();
|
|
|
|
|
|
|
|
glDisable(GL_LINE_STIPPLE);
|
|
|
|
glEnable(GL_DEPTH_TEST);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Project::RenderViewports(bool bBackground, bool bLines)
|
|
|
|
{
|
|
|
|
float x, y, w, h;
|
|
|
|
int vp;
|
|
|
|
|
|
|
|
glViewport(0, 0, m_nViewX, m_nViewY);
|
|
|
|
glMatrixMode(GL_PROJECTION);
|
|
|
|
glLoadIdentity();
|
|
|
|
glOrtho(0, m_nViewX, 0, m_nViewY, -1, 1);
|
|
|
|
glMatrixMode(GL_MODELVIEW);
|
|
|
|
glLoadIdentity();
|
|
|
|
glTranslatef(0.375, 0.375, 0.0);
|
|
|
|
|
|
|
|
if (bBackground)
|
|
|
|
{
|
|
|
|
// Draw gradient
|
|
|
|
if (m_nScene & LC_SCENE_GRADIENT)
|
|
|
|
{
|
|
|
|
if ((m_nDetail & LC_DET_SMOOTH) == 0)
|
|
|
|
glShadeModel(GL_SMOOTH);
|
|
|
|
glDisable(GL_DEPTH_TEST);
|
|
|
|
glBegin(GL_QUADS);
|
|
|
|
|
|
|
|
for (vp = 0; vp < viewports[m_nViewportMode].n; vp++)
|
|
|
|
{
|
|
|
|
x = viewports[m_nViewportMode].dim[vp][0] * (float)m_nViewX;
|
|
|
|
y = viewports[m_nViewportMode].dim[vp][1] * (float)m_nViewY;
|
|
|
|
w = viewports[m_nViewportMode].dim[vp][2] * (float)m_nViewX;
|
|
|
|
h = viewports[m_nViewportMode].dim[vp][3] * (float)m_nViewY;
|
|
|
|
|
|
|
|
glColor3fv(m_fGradient1);
|
|
|
|
glVertex2f(x+w, y+h);
|
|
|
|
glVertex2f(x, y+h);
|
|
|
|
glColor3fv(m_fGradient2);
|
|
|
|
glVertex2f(x, y);
|
|
|
|
glVertex2f(x+w, y);
|
|
|
|
}
|
|
|
|
glEnd();
|
|
|
|
glEnable(GL_DEPTH_TEST);
|
|
|
|
if ((m_nDetail & LC_DET_SMOOTH) == 0)
|
|
|
|
glShadeModel(GL_FLAT);
|
|
|
|
}
|
|
|
|
|
|
|
|
glEnable(GL_TEXTURE_2D);
|
|
|
|
|
|
|
|
// Draw the background
|
|
|
|
if (m_nScene & LC_SCENE_BG)
|
|
|
|
{
|
|
|
|
glDisable (GL_DEPTH_TEST);
|
|
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
|
|
|
|
m_pBackground->MakeCurrent();
|
|
|
|
glBegin(GL_QUADS);
|
|
|
|
|
|
|
|
for (vp = 0; vp < viewports[m_nViewportMode].n; vp++)
|
|
|
|
{
|
|
|
|
x = viewports[m_nViewportMode].dim[vp][0] * (float)m_nViewX;
|
|
|
|
y = viewports[m_nViewportMode].dim[vp][1] * (float)m_nViewY;
|
|
|
|
w = viewports[m_nViewportMode].dim[vp][2] * (float)m_nViewX;
|
|
|
|
h = viewports[m_nViewportMode].dim[vp][3] * (float)m_nViewY;
|
|
|
|
|
|
|
|
float tw = 1.0f, th = 1.0f;
|
|
|
|
if (m_nScene & LC_SCENE_BG_TILE)
|
|
|
|
{
|
|
|
|
tw = w/m_pBackground->m_nWidth;
|
|
|
|
th = h/m_pBackground->m_nHeight;
|
|
|
|
}
|
|
|
|
|
|
|
|
glTexCoord2f(0, 0);
|
|
|
|
glVertex2f(x, y+h);
|
|
|
|
glTexCoord2f(tw, 0);
|
|
|
|
glVertex2f(x+w, y+h);
|
|
|
|
glTexCoord2f(tw, th);
|
|
|
|
glVertex2f(x+w, y);
|
|
|
|
glTexCoord2f(0, th);
|
|
|
|
glVertex2f(x, y);
|
|
|
|
}
|
|
|
|
glEnd();
|
|
|
|
glEnable(GL_DEPTH_TEST);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!bLines)
|
|
|
|
glDisable(GL_TEXTURE_2D);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (bLines)
|
|
|
|
{
|
|
|
|
// Draw text
|
|
|
|
glColor3f(0, 0, 0);
|
|
|
|
if (!bBackground)
|
|
|
|
glEnable(GL_TEXTURE_2D);
|
|
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
|
|
|
|
m_pScreenFont->MakeCurrent();
|
|
|
|
glEnable(GL_ALPHA_TEST);
|
|
|
|
glBegin(GL_QUADS);
|
|
|
|
|
|
|
|
for (vp = 0; vp < viewports[m_nViewportMode].n; vp++)
|
|
|
|
{
|
|
|
|
x = viewports[m_nViewportMode].dim[vp][0] * (float)m_nViewX;
|
|
|
|
y = viewports[m_nViewportMode].dim[vp][1] * (float)m_nViewY;
|
|
|
|
w = viewports[m_nViewportMode].dim[vp][2] * (float)(m_nViewX - 1);
|
|
|
|
h = viewports[m_nViewportMode].dim[vp][3] * (float)(m_nViewY - 1);
|
|
|
|
|
|
|
|
m_pScreenFont->PrintText(x + 3, y + h - 6, 0.0f, m_pViewCameras[vp]->GetName());
|
|
|
|
}
|
|
|
|
glEnd();
|
|
|
|
|
|
|
|
glDisable(GL_ALPHA_TEST);
|
|
|
|
glDisable(GL_TEXTURE_2D);
|
|
|
|
|
|
|
|
// Borders
|
|
|
|
if (m_fLineWidth != 1.0f)
|
|
|
|
glLineWidth (1.0f);
|
|
|
|
|
|
|
|
for (vp = 0; vp < viewports[m_nViewportMode].n; vp++)
|
|
|
|
{
|
|
|
|
if (vp == m_nActiveViewport)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
x = viewports[m_nViewportMode].dim[vp][0] * (float)m_nViewX;
|
|
|
|
y = viewports[m_nViewportMode].dim[vp][1] * (float)m_nViewY;
|
|
|
|
w = viewports[m_nViewportMode].dim[vp][2] * (float)(m_nViewX - 1);
|
|
|
|
h = viewports[m_nViewportMode].dim[vp][3] * (float)(m_nViewY - 1);
|
|
|
|
|
|
|
|
glBegin(GL_LINE_LOOP);
|
|
|
|
glVertex2f(x, y);
|
|
|
|
glVertex2f(x+w, y);
|
|
|
|
glVertex2f(x+w, y+h);
|
|
|
|
glVertex2f(x, y+h);
|
|
|
|
glEnd();
|
|
|
|
}
|
|
|
|
|
|
|
|
x = viewports[m_nViewportMode].dim[m_nActiveViewport][0] * (float)m_nViewX;
|
|
|
|
y = viewports[m_nViewportMode].dim[m_nActiveViewport][1] * (float)m_nViewY;
|
|
|
|
w = viewports[m_nViewportMode].dim[m_nActiveViewport][2] * (float)(m_nViewX - 1);
|
|
|
|
h = viewports[m_nViewportMode].dim[m_nActiveViewport][3] * (float)(m_nViewY - 1);
|
|
|
|
|
|
|
|
glColor3f(1.0f, 0, 0);
|
|
|
|
glBegin(GL_LINE_LOOP);
|
|
|
|
glVertex2f(x, y);
|
|
|
|
glVertex2f(x+w, y);
|
|
|
|
glVertex2f(x+w, y+h);
|
|
|
|
glVertex2f(x, y+h);
|
|
|
|
glEnd();
|
|
|
|
|
|
|
|
if (m_fLineWidth != 1.0f)
|
|
|
|
glLineWidth (m_fLineWidth);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// bHilite - Draws focus/selection, not used for the
|
|
|
|
// first rendering pass if remove hidden lines is enabled
|
|
|
|
void Project::RenderBoxes(bool bHilite)
|
|
|
|
{
|
|
|
|
Piece* pPiece;
|
|
|
|
|
|
|
|
for (pPiece = m_pPieces; pPiece; pPiece = pPiece->m_pNext)
|
|
|
|
if (pPiece->IsVisible(m_bAnimation ? m_nCurFrame : m_nCurStep, m_bAnimation))
|
|
|
|
pPiece->RenderBox(bHilite, m_fLineWidth);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Initialize OpenGL
|
|
|
|
void Project::RenderInitialize()
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
|
|
|
|
|
|
|
glEnable(GL_POLYGON_OFFSET_FILL);
|
|
|
|
glPolygonOffset(0.5f, 0.1f);
|
|
|
|
|
|
|
|
glCullFace(GL_BACK);
|
|
|
|
glDisable (GL_CULL_FACE);
|
|
|
|
|
|
|
|
glEnable(GL_DEPTH_TEST);
|
|
|
|
glDepthFunc(GL_LEQUAL);
|
|
|
|
glDepthMask(GL_TRUE);
|
|
|
|
|
|
|
|
if (m_nDetail & LC_DET_SMOOTH)
|
|
|
|
glShadeModel(GL_SMOOTH);
|
|
|
|
else
|
|
|
|
glShadeModel(GL_FLAT);
|
|
|
|
|
|
|
|
if (m_nDetail & LC_DET_LIGHTING)
|
|
|
|
{
|
2011-09-20 01:03:28 +02:00
|
|
|
glEnable(GL_LIGHTING);
|
|
|
|
glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT);
|
|
|
|
glEnable(GL_COLOR_MATERIAL);
|
2011-09-07 23:06:51 +02:00
|
|
|
|
2011-09-20 01:03:28 +02:00
|
|
|
GLfloat mat_translucent[] = { (GLfloat)0.8, (GLfloat)0.8, (GLfloat)0.8, (GLfloat)1.0 };
|
|
|
|
GLfloat mat_opaque[] = { (GLfloat)0.8, (GLfloat)0.8, (GLfloat)0.8, (GLfloat)1.0 };
|
|
|
|
GLfloat medium_shininess[] = { (GLfloat)64.0 };
|
2011-09-07 23:06:51 +02:00
|
|
|
|
2011-09-20 01:03:28 +02:00
|
|
|
glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, medium_shininess);
|
|
|
|
glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, mat_opaque);
|
|
|
|
glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mat_translucent);
|
2011-09-07 23:06:51 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
glDisable(GL_LIGHTING);
|
|
|
|
glDisable(GL_COLOR_MATERIAL);
|
|
|
|
}
|
|
|
|
|
|
|
|
glLightModelfv(GL_LIGHT_MODEL_AMBIENT, m_fAmbient);
|
|
|
|
glClearColor(m_fBackground[0], m_fBackground[1], m_fBackground[2], 1.0f);
|
|
|
|
|
|
|
|
if (m_nScene & LC_SCENE_FOG)
|
|
|
|
{
|
|
|
|
glEnable(GL_FOG);
|
|
|
|
glFogi(GL_FOG_MODE, GL_EXP);
|
|
|
|
glFogf(GL_FOG_DENSITY, m_fFogDensity);
|
|
|
|
glFogfv(GL_FOG_COLOR, m_fFogColor);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
glDisable (GL_FOG);
|
|
|
|
|
|
|
|
// Load font
|
2011-09-20 01:03:28 +02:00
|
|
|
if (!m_pScreenFont->IsLoaded())
|
|
|
|
{
|
|
|
|
char filename[LC_MAXPATH];
|
|
|
|
FileDisk file;
|
2011-09-07 23:06:51 +02:00
|
|
|
|
2011-09-20 01:03:28 +02:00
|
|
|
strcpy(filename, lcGetPiecesLibrary()->GetLibraryPath());
|
|
|
|
strcat(filename, "sysfont.txf");
|
2011-09-07 23:06:51 +02:00
|
|
|
|
2011-09-20 01:03:28 +02:00
|
|
|
if (file.Open(filename, "rb"))
|
|
|
|
m_pScreenFont->FileLoad(file);
|
|
|
|
}
|
2011-09-07 23:06:51 +02:00
|
|
|
|
|
|
|
glAlphaFunc(GL_GREATER, 0.0625);
|
|
|
|
|
|
|
|
if (m_nScene & LC_SCENE_FLOOR)
|
2011-09-20 01:03:28 +02:00
|
|
|
m_pTerrain->LoadTexture(true);
|
2011-09-07 23:06:51 +02:00
|
|
|
|
|
|
|
if (m_nScene & LC_SCENE_BG)
|
2011-09-20 01:03:28 +02:00
|
|
|
if (!m_pBackground->LoadFromFile(m_strBackground, true))
|
2011-09-07 23:06:51 +02:00
|
|
|
{
|
|
|
|
m_nScene &= ~LC_SCENE_BG;
|
|
|
|
// AfxMessageBox ("Could not load background");
|
|
|
|
}
|
|
|
|
|
|
|
|
// Set the perspective correction hint to fastest or nicest...
|
|
|
|
// glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST);
|
|
|
|
|
|
|
|
// 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++)
|
|
|
|
{
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
glVertexPointer(3, GL_FLOAT, 0, grid);
|
|
|
|
glDrawArrays(GL_LINES, 0, i);
|
|
|
|
glEndList();
|
|
|
|
free(grid);
|
|
|
|
}
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
// Project functions
|
|
|
|
|
|
|
|
void Project::AddPiece(Piece* pPiece)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
// Sort piece array to avoid OpenGL state changes (needs work)
|
|
|
|
void CCADDoc::AddPiece(CPiece* pNewPiece)
|
|
|
|
{
|
|
|
|
POSITION pos1, pos2;
|
|
|
|
|
|
|
|
for (pos1 = m_Pieces.GetHeadPosition(); (pos2 = pos1) != NULL;)
|
|
|
|
{
|
|
|
|
CPiece* pPiece = m_Pieces.GetNext(pos1);
|
|
|
|
if (pPiece->IsTransparent())
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (pos2 == NULL || pNewPiece->IsTransparent())
|
|
|
|
m_Pieces.AddTail(pNewPiece);
|
|
|
|
else
|
|
|
|
m_Pieces.InsertBefore(pos2, pNewPiece);
|
|
|
|
}
|
|
|
|
*/
|
|
|
|
if (m_pPieces != NULL)
|
|
|
|
{
|
|
|
|
pPiece->m_pNext = m_pPieces;
|
|
|
|
m_pPieces = pPiece;
|
|
|
|
// TODO: sorting and BSP
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
m_pPieces = pPiece;
|
|
|
|
pPiece->m_pNext = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
pPiece->AddConnections(m_pConnections);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Project::RemovePiece(Piece* pPiece)
|
|
|
|
{
|
|
|
|
Piece* pTemp, *pLast;
|
|
|
|
pLast = NULL;
|
|
|
|
|
|
|
|
for (pTemp = m_pPieces; pTemp; pLast = pTemp, pTemp = pTemp->m_pNext)
|
|
|
|
if (pTemp == pPiece)
|
|
|
|
{
|
|
|
|
if (pLast != NULL)
|
|
|
|
pLast->m_pNext = pTemp->m_pNext;
|
|
|
|
else
|
|
|
|
m_pPieces = pTemp->m_pNext;
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
pPiece->RemoveConnections(m_pConnections);
|
|
|
|
|
|
|
|
// TODO: remove from BSP
|
|
|
|
}
|
|
|
|
|
|
|
|
void Project::CalculateStep()
|
|
|
|
{
|
|
|
|
int PieceCount = 0;
|
|
|
|
Piece* pPiece;
|
|
|
|
Camera* pCamera;
|
|
|
|
Light* pLight;
|
|
|
|
|
|
|
|
for (pPiece = m_pPieces; pPiece; pPiece = pPiece->m_pNext)
|
|
|
|
{
|
|
|
|
pPiece->UpdatePosition(m_bAnimation ? m_nCurFrame : m_nCurStep, m_bAnimation);
|
|
|
|
PieceCount++;
|
|
|
|
}
|
|
|
|
|
|
|
|
SystemDoWaitCursor(1);
|
|
|
|
SystemStartProgressBar(0, PieceCount, 1, "Updating pieces...");
|
|
|
|
|
|
|
|
for (pPiece = m_pPieces; pPiece; pPiece = pPiece->m_pNext)
|
|
|
|
{
|
|
|
|
pPiece->CalculateConnections(m_pConnections, m_bAnimation ? m_nCurFrame : m_nCurStep, m_bAnimation, false, false);
|
|
|
|
SytemStepProgressBar();
|
|
|
|
}
|
|
|
|
|
|
|
|
SytemEndProgressBar();
|
|
|
|
SystemDoWaitCursor(-1);
|
|
|
|
|
|
|
|
for (pCamera = m_pCameras; pCamera; pCamera = pCamera->m_pNext)
|
|
|
|
pCamera->UpdatePosition(m_bAnimation ? m_nCurFrame : m_nCurStep, m_bAnimation);
|
|
|
|
|
|
|
|
for (pLight = m_pLights; pLight; pLight = pLight->m_pNext)
|
|
|
|
pLight->UpdatePosition(m_bAnimation ? m_nCurFrame : m_nCurStep, m_bAnimation);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Returns true if anything was removed (used by cut and del)
|
|
|
|
bool Project::RemoveSelectedObjects()
|
|
|
|
{
|
|
|
|
Piece* pPiece;
|
|
|
|
Camera* pCamera;
|
|
|
|
Light* pLight;
|
|
|
|
void* pPrev;
|
|
|
|
bool removed = false;
|
|
|
|
|
|
|
|
pPiece = m_pPieces;
|
|
|
|
while (pPiece)
|
|
|
|
{
|
|
|
|
if (pPiece->IsSelected())
|
|
|
|
{
|
|
|
|
Piece* pTemp;
|
|
|
|
pTemp = pPiece->m_pNext;
|
|
|
|
|
|
|
|
removed = true;
|
|
|
|
RemovePiece(pPiece);
|
|
|
|
delete pPiece;
|
|
|
|
pPiece = pTemp;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
pPiece = pPiece->m_pNext;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Cameras can't be removed while being used or default
|
|
|
|
for (pPrev = NULL, pCamera = m_pCameras; pCamera; )
|
|
|
|
{
|
|
|
|
bool bCanDelete = true;
|
|
|
|
for (int i = 0; i < 4; i++)
|
|
|
|
{
|
|
|
|
if (pCamera == m_pViewCameras[i])
|
|
|
|
{
|
|
|
|
bCanDelete = false;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (bCanDelete && pCamera->IsSelected() && pCamera->IsUser())
|
|
|
|
{
|
|
|
|
if (pPrev)
|
|
|
|
{
|
|
|
|
((Camera*)pPrev)->m_pNext = pCamera->m_pNext;
|
|
|
|
delete pCamera;
|
|
|
|
pCamera = ((Camera*)pPrev)->m_pNext;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
m_pCameras = m_pCameras->m_pNext;
|
|
|
|
delete pCamera;
|
|
|
|
pCamera = m_pCameras;
|
|
|
|
}
|
|
|
|
|
|
|
|
removed = true;
|
|
|
|
|
|
|
|
SystemUpdateCameraMenu(m_pCameras);
|
|
|
|
SystemUpdateCurrentCamera(NULL, m_pViewCameras[m_nActiveViewport], m_pCameras);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
pPrev = pCamera;
|
|
|
|
pCamera = pCamera->m_pNext;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for (pPrev = NULL, pLight = m_pLights; pLight; )
|
|
|
|
{
|
|
|
|
if (pLight->IsSelected())
|
|
|
|
{
|
|
|
|
if (pPrev)
|
|
|
|
{
|
|
|
|
((Light*)pPrev)->m_pNext = pLight->m_pNext;
|
|
|
|
delete pLight;
|
|
|
|
pLight = ((Light*)pPrev)->m_pNext;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
m_pLights = m_pLights->m_pNext;
|
|
|
|
delete pLight;
|
|
|
|
pLight = m_pLights;
|
|
|
|
}
|
|
|
|
|
|
|
|
removed = true;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
pPrev = pLight;
|
|
|
|
pLight = pLight->m_pNext;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
RemoveEmptyGroups();
|
|
|
|
// CalculateStep();
|
|
|
|
// AfxGetMainWnd()->PostMessage(WM_LC_UPDATE_INFO, NULL, OT_PIECE);
|
|
|
|
|
|
|
|
return removed;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Project::UpdateSelection()
|
|
|
|
{
|
|
|
|
unsigned long flags = 0;
|
|
|
|
int SelectedCount = 0;
|
|
|
|
Object* Focus = NULL;
|
|
|
|
|
|
|
|
if (m_pPieces == NULL)
|
|
|
|
flags |= LC_SEL_NO_PIECES;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
Piece* pPiece;
|
|
|
|
Group* pGroup = NULL;
|
|
|
|
bool first = true;
|
|
|
|
|
|
|
|
for (pPiece = m_pPieces; pPiece; pPiece = pPiece->m_pNext)
|
|
|
|
{
|
|
|
|
if (pPiece->IsSelected())
|
|
|
|
{
|
|
|
|
SelectedCount++;
|
|
|
|
|
|
|
|
if (pPiece->IsFocused())
|
|
|
|
Focus = pPiece;
|
|
|
|
|
|
|
|
if (flags & LC_SEL_PIECE)
|
|
|
|
flags |= LC_SEL_MULTIPLE;
|
|
|
|
else
|
|
|
|
flags |= LC_SEL_PIECE;
|
|
|
|
|
|
|
|
if (pPiece->GetGroup() != NULL)
|
|
|
|
{
|
|
|
|
flags |= LC_SEL_GROUP;
|
|
|
|
if (pPiece->IsFocused())
|
|
|
|
flags |= LC_SEL_FOCUSGROUP;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (first)
|
|
|
|
{
|
|
|
|
pGroup = pPiece->GetGroup();
|
|
|
|
first = false;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (pGroup != pPiece->GetGroup())
|
|
|
|
flags |= LC_SEL_CANGROUP;
|
|
|
|
else
|
|
|
|
if (pGroup == NULL)
|
|
|
|
flags |= LC_SEL_CANGROUP;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
flags |= LC_SEL_UNSELECTED;
|
|
|
|
|
|
|
|
if (pPiece->IsHidden())
|
|
|
|
flags |= LC_SEL_HIDDEN;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for (Camera* pCamera = m_pCameras; pCamera; pCamera = pCamera->m_pNext)
|
|
|
|
if (pCamera->IsSelected())
|
|
|
|
{
|
|
|
|
flags |= LC_SEL_CAMERA;
|
|
|
|
SelectedCount++;
|
|
|
|
|
|
|
|
if (pCamera->IsEyeFocused() || pCamera->IsTargetFocused())
|
|
|
|
Focus = pCamera;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (Light* pLight = m_pLights; pLight; pLight = pLight->m_pNext)
|
|
|
|
if (pLight->IsSelected())
|
|
|
|
{
|
|
|
|
flags |= LC_SEL_LIGHT;
|
|
|
|
SelectedCount++;
|
|
|
|
|
|
|
|
if (pLight->IsEyeFocused() || pLight->IsTargetFocused())
|
|
|
|
Focus = pLight;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (m_nTracking == LC_TRACK_NONE)
|
|
|
|
{
|
|
|
|
ActivateOverlay();
|
|
|
|
}
|
|
|
|
|
|
|
|
SystemUpdateSelected(flags, SelectedCount, Focus);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Project::CheckAutoSave()
|
|
|
|
{
|
|
|
|
m_nSaveTimer += 5;
|
|
|
|
if (m_nAutosave & LC_AUTOSAVE_FLAG)
|
|
|
|
{
|
|
|
|
int nInterval;
|
|
|
|
nInterval = m_nAutosave & ~LC_AUTOSAVE_FLAG;
|
|
|
|
|
|
|
|
if (m_nSaveTimer >= (m_nAutosave*60))
|
|
|
|
{
|
|
|
|
m_nSaveTimer = 0;
|
|
|
|
/*
|
|
|
|
if (m_strTempFile.IsEmpty())
|
|
|
|
{
|
|
|
|
char tmpFile[_MAX_PATH], out[_MAX_PATH];
|
|
|
|
GetTempPath (_MAX_PATH, out);
|
|
|
|
GetTempFileName (out, "~LC", 0, tmpFile);
|
|
|
|
DeleteFile (tmpFile);
|
|
|
|
if (char *ptr = strchr(tmpFile, '.')) *ptr = 0;
|
|
|
|
strcat (tmpFile, ".lcd");
|
|
|
|
m_strTempFile = tmpFile;
|
|
|
|
}
|
|
|
|
|
|
|
|
CFile file (m_strTempFile, CFile::modeCreate|CFile::modeWrite|CFile::typeBinary);
|
|
|
|
m_bUndo = TRUE;
|
|
|
|
file.SeekToBegin();
|
|
|
|
CArchive ar(&file, CArchive::store);
|
|
|
|
Serialize(ar);
|
|
|
|
ar.Close();
|
|
|
|
m_bUndo = FALSE;
|
|
|
|
*/ }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Project::SetViewSize(int cx, int cy)
|
|
|
|
{
|
|
|
|
m_nViewX = cx;
|
|
|
|
m_nViewY = (cy != 0) ? cy : 1; // Avoid divide by zero.
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned char Project::GetLastStep()
|
|
|
|
{
|
|
|
|
unsigned char last = 1;
|
|
|
|
for (Piece* pPiece = m_pPieces; pPiece; pPiece = pPiece->m_pNext)
|
|
|
|
last = max(last, pPiece->GetStepShow());
|
|
|
|
|
|
|
|
return last;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Create a series of pictures
|
|
|
|
void Project::CreateImages (Image* images, int width, int height, unsigned short from, unsigned short to, bool hilite)
|
|
|
|
{
|
|
|
|
int oldx, oldy;
|
|
|
|
unsigned short oldtime;
|
|
|
|
void* render = Sys_StartMemoryRender (width, height);
|
|
|
|
unsigned char* buf = (unsigned char*)malloc (width*height*3);
|
|
|
|
oldtime = m_bAnimation ? m_nCurFrame : m_nCurStep;
|
|
|
|
oldx = m_nViewX;
|
|
|
|
oldy = m_nViewY;
|
|
|
|
m_nViewX = width;
|
|
|
|
m_nViewY = height;
|
|
|
|
|
|
|
|
if (!hilite)
|
|
|
|
SelectAndFocusNone(false);
|
|
|
|
|
|
|
|
RenderInitialize();
|
|
|
|
|
|
|
|
// CCamera* pOld = pDoc->GetActiveCamera();
|
|
|
|
// pDoc->m_ViewCameras[pDoc->m_nActiveViewport] = pDoc->GetCamera(CAMERA_MAIN);
|
|
|
|
for (int i = from; i <= to; i++)
|
|
|
|
{
|
|
|
|
if (m_bAnimation)
|
|
|
|
m_nCurFrame = i;
|
|
|
|
else
|
|
|
|
m_nCurStep = i;
|
|
|
|
|
|
|
|
if (hilite)
|
|
|
|
{
|
|
|
|
for (Piece* pPiece = m_pPieces; pPiece; pPiece = pPiece->m_pNext)
|
|
|
|
{
|
|
|
|
if ((m_bAnimation && pPiece->GetFrameShow() == i) ||
|
|
|
|
(!m_bAnimation && pPiece->GetStepShow() == i))
|
|
|
|
pPiece->Select (true, false, false);
|
|
|
|
else
|
|
|
|
pPiece->Select (false, false, false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
CalculateStep();
|
|
|
|
Render(true);
|
|
|
|
images[i-from].FromOpenGL (width, height);
|
|
|
|
}
|
|
|
|
// pDoc->m_ViewCameras[pDoc->m_nActiveViewport] = pOld;
|
|
|
|
m_nViewX = oldx;
|
|
|
|
m_nViewY = oldy;
|
|
|
|
if (m_bAnimation)
|
|
|
|
m_nCurFrame = oldtime;
|
|
|
|
else
|
|
|
|
m_nCurStep = (unsigned char)oldtime;
|
|
|
|
CalculateStep();
|
|
|
|
free (buf);
|
|
|
|
Sys_FinishMemoryRender (render);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Project::CreateHTMLPieceList(FILE* f, int nStep, bool bImages, const char* ext)
|
|
|
|
{
|
|
|
|
Piece* pPiece;
|
|
|
|
int col[LC_MAXCOLORS], ID = 0, c;
|
|
|
|
memset (&col, 0, sizeof (col));
|
|
|
|
for (pPiece = m_pPieces; pPiece; pPiece = pPiece->m_pNext)
|
|
|
|
{
|
|
|
|
if ((pPiece->GetStepShow() == nStep) || (nStep == 0))
|
|
|
|
col[pPiece->GetColor()]++;
|
|
|
|
}
|
|
|
|
fputs("<br><table border=1><tr><td><center>Piece</center></td>\n",f);
|
|
|
|
|
|
|
|
for (c = 0; c < LC_MAXCOLORS; c++)
|
|
|
|
if (col[c])
|
|
|
|
{
|
|
|
|
col[c] = ID;
|
|
|
|
ID++;
|
|
|
|
fprintf(f, "<td><center>%s</center></td>\n", colornames[c]);
|
|
|
|
}
|
|
|
|
ID++;
|
|
|
|
fputs("</tr>\n",f);
|
|
|
|
|
|
|
|
PieceInfo* pInfo;
|
|
|
|
for (int j = 0; j < lcGetPiecesLibrary()->GetPieceCount (); j++)
|
|
|
|
{
|
|
|
|
bool Add = false;
|
|
|
|
int count[LC_MAXCOLORS];
|
|
|
|
memset (&count, 0, sizeof (count));
|
|
|
|
pInfo = lcGetPiecesLibrary()->GetPieceInfo (j);
|
|
|
|
|
|
|
|
for (pPiece = m_pPieces; pPiece; pPiece = pPiece->m_pNext)
|
|
|
|
{
|
|
|
|
if ((pPiece->GetPieceInfo() == pInfo) &&
|
|
|
|
((pPiece->GetStepShow() == nStep) || (nStep == 0)))
|
|
|
|
{
|
|
|
|
count [pPiece->GetColor()]++;
|
|
|
|
Add = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Add)
|
|
|
|
{
|
|
|
|
if (bImages)
|
|
|
|
fprintf(f, "<tr><td><IMG SRC=\"%s%s\" ALT=\"%s\"></td>\n", pInfo->m_strName, ext, pInfo->m_strDescription);
|
|
|
|
else
|
|
|
|
fprintf(f, "<tr><td>%s</td>\n", pInfo->m_strDescription);
|
|
|
|
|
|
|
|
int curcol = 1;
|
|
|
|
for (c = 0; c < LC_MAXCOLORS; c++)
|
|
|
|
if (count[c])
|
|
|
|
{
|
|
|
|
while (curcol != col[c] + 1)
|
|
|
|
{
|
|
|
|
fputs("<td><center>-</center></td>\n", f);
|
|
|
|
curcol++;
|
|
|
|
}
|
|
|
|
|
|
|
|
fprintf(f, "<td><center>%d</center></td>\n", count[c]);
|
|
|
|
curcol++;
|
|
|
|
}
|
|
|
|
|
|
|
|
while (curcol != ID)
|
|
|
|
{
|
|
|
|
fputs("<td><center>-</center></td>\n", f);
|
|
|
|
curcol++;
|
|
|
|
}
|
|
|
|
|
|
|
|
fputs("</tr>\n", f);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
fputs("</table>\n<br>", f);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Special notifications.
|
|
|
|
void Project::HandleNotify(LC_NOTIFY id, unsigned long param)
|
|
|
|
{
|
|
|
|
switch (id)
|
|
|
|
{
|
|
|
|
case LC_COLOR_CHANGED:
|
|
|
|
{
|
|
|
|
m_nCurColor = (unsigned char)param;
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case LC_CAPTURE_LOST:
|
|
|
|
{
|
|
|
|
if (m_nTracking != LC_TRACK_NONE)
|
|
|
|
StopTracking(false);
|
|
|
|
} break;
|
|
|
|
|
|
|
|
// Application is (de)activated
|
|
|
|
case LC_ACTIVATE:
|
|
|
|
{
|
|
|
|
if (param == 0)
|
|
|
|
SystemExportClipboard(m_pClipboard[m_nCurClipboard]);
|
|
|
|
else
|
|
|
|
{
|
|
|
|
free(m_pClipboard[m_nCurClipboard]);
|
|
|
|
m_pClipboard[m_nCurClipboard] = SystemImportClipboard();
|
|
|
|
SystemUpdatePaste(m_pClipboard[m_nCurClipboard] != NULL);
|
|
|
|
}
|
|
|
|
} break;
|
|
|
|
|
|
|
|
// FIXME: don't change the keys with ChangeKey()
|
|
|
|
// FIXME: even if pos == prevpos, the user might want to add a key
|
|
|
|
|
|
|
|
case LC_PIECE_MODIFIED:
|
|
|
|
{
|
|
|
|
LC_PIECE_MODIFY* mod = (LC_PIECE_MODIFY*)param;
|
|
|
|
Piece* pPiece = (Piece*)mod->piece;
|
|
|
|
|
|
|
|
float rot[4];
|
|
|
|
Vector3 Pos = pPiece->GetPosition();
|
|
|
|
pPiece->GetRotation(rot);
|
|
|
|
Matrix mat(rot, Pos);
|
|
|
|
mat.ToEulerAngles(rot);
|
|
|
|
|
|
|
|
if (Pos != mod->Position)
|
|
|
|
pPiece->ChangeKey(m_bAnimation ? m_nCurFrame : m_nCurStep, m_bAnimation, m_bAddKeys, mod->Position, LC_PK_POSITION);
|
|
|
|
|
|
|
|
if (mod->Rotation[0] != rot[0] || mod->Rotation[1] != rot[1] || mod->Rotation[2] != rot[2])
|
|
|
|
{
|
|
|
|
mat.FromEulerAngles(mod->Rotation[0], mod->Rotation[1], mod->Rotation[2]);
|
|
|
|
mat.ToAxisAngle(rot);
|
|
|
|
pPiece->ChangeKey(m_bAnimation ? m_nCurFrame : m_nCurStep, m_bAnimation, m_bAddKeys, rot, LC_PK_ROTATION);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (m_bAnimation)
|
|
|
|
{
|
|
|
|
pPiece->SetFrameShow(mod->from);
|
|
|
|
pPiece->SetFrameHide(mod->to);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
pPiece->SetStepShow(mod->from);
|
|
|
|
pPiece->SetStepHide(mod->to);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (mod->hidden)
|
|
|
|
pPiece->Hide();
|
|
|
|
else
|
|
|
|
pPiece->UnHide();
|
|
|
|
|
|
|
|
pPiece->SetName(mod->name);
|
|
|
|
pPiece->SetColor(mod->color);
|
|
|
|
pPiece->UpdatePosition(m_bAnimation ? m_nCurFrame : m_nCurStep, m_bAnimation);
|
|
|
|
pPiece->CalculateConnections(m_pConnections, m_bAnimation ? m_nCurFrame : m_nCurStep, m_bAnimation, false, true);
|
|
|
|
|
|
|
|
SetModifiedFlag(true);
|
|
|
|
CheckPoint("Modifying");
|
|
|
|
ActivateOverlay();
|
|
|
|
UpdateAllViews();
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case LC_CAMERA_MODIFIED:
|
|
|
|
{
|
|
|
|
LC_CAMERA_MODIFY* mod = (LC_CAMERA_MODIFY*)param;
|
|
|
|
Camera* pCamera = (Camera*)mod->camera;
|
|
|
|
|
|
|
|
if (mod->hidden)
|
|
|
|
pCamera->Hide();
|
|
|
|
else
|
|
|
|
pCamera->UnHide();
|
|
|
|
|
|
|
|
if (pCamera->GetEyePosition() != mod->Eye)
|
|
|
|
pCamera->ChangeKey(m_bAnimation ? m_nCurFrame : m_nCurStep, m_bAnimation, m_bAddKeys, mod->Eye, LC_CK_EYE);
|
|
|
|
|
|
|
|
if (pCamera->GetTargetPosition() != mod->Target)
|
|
|
|
pCamera->ChangeKey(m_bAnimation ? m_nCurFrame : m_nCurStep, m_bAnimation, m_bAddKeys, mod->Target, LC_CK_TARGET);
|
|
|
|
|
|
|
|
if (pCamera->GetUpVector() != mod->Up)
|
|
|
|
pCamera->ChangeKey(m_bAnimation ? m_nCurFrame : m_nCurStep, m_bAnimation, m_bAddKeys, mod->Up, LC_CK_UP);
|
|
|
|
|
|
|
|
pCamera->m_fovy = mod->fovy;
|
|
|
|
pCamera->m_zNear = mod->znear;
|
|
|
|
pCamera->m_zFar = mod->zfar;
|
|
|
|
pCamera->UpdatePosition(m_bAnimation ? m_nCurFrame : m_nCurStep, m_bAnimation);
|
|
|
|
UpdateAllViews ();
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case LC_LIGHT_MODIFIED:
|
|
|
|
{
|
|
|
|
} break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Project::HandleMessage(int Message, void* Data)
|
|
|
|
{
|
|
|
|
if (Message == LC_MSG_FOCUS_CHANGED)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Handle (almost) all menu/toolbar commands here.
|
|
|
|
void Project::HandleCommand(LC_COMMANDS id, unsigned long nParam)
|
|
|
|
{
|
|
|
|
switch (id)
|
|
|
|
{
|
|
|
|
case LC_FILE_NEW:
|
|
|
|
{
|
|
|
|
if (!SaveModified())
|
|
|
|
return; // leave the original one
|
|
|
|
|
|
|
|
OnNewDocument();
|
|
|
|
UpdateAllViews ();
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case LC_FILE_OPEN:
|
|
|
|
{
|
|
|
|
char filename[LC_MAXPATH];
|
|
|
|
strcpy(filename, m_strModelsPath);
|
|
|
|
|
|
|
|
if (SystemDoDialog(LC_DLG_FILE_OPEN_PROJECT, filename))
|
|
|
|
{
|
|
|
|
OpenProject(filename);
|
|
|
|
}
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case LC_FILE_MERGE:
|
|
|
|
{
|
|
|
|
char filename[LC_MAXPATH];
|
|
|
|
strcpy(filename, m_strModelsPath);
|
|
|
|
|
|
|
|
if (SystemDoDialog(LC_DLG_FILE_MERGE_PROJECT, filename))
|
|
|
|
{
|
|
|
|
FileDisk file;
|
|
|
|
if (file.Open(filename, "rb"))
|
|
|
|
{
|
|
|
|
// CWaitCursor wait;
|
|
|
|
if (file.GetLength() != 0)
|
|
|
|
{
|
|
|
|
FileLoad(&file, false, true);
|
|
|
|
CheckPoint("Merging");
|
|
|
|
}
|
|
|
|
file.Close();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case LC_FILE_SAVE:
|
|
|
|
{
|
|
|
|
DoFileSave();
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case LC_FILE_SAVEAS:
|
|
|
|
{
|
|
|
|
DoSave(NULL, true);
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case LC_FILE_PICTURE:
|
|
|
|
{
|
|
|
|
LC_IMAGEDLG_OPTS opts;
|
|
|
|
opts.from = 1;
|
|
|
|
opts.to = m_bAnimation ? m_nTotalFrames : GetLastStep();
|
|
|
|
opts.multiple = m_bAnimation;
|
|
|
|
opts.imopts.background[0] = (unsigned char)(m_fBackground[0]*255);
|
|
|
|
opts.imopts.background[1] = (unsigned char)(m_fBackground[1]*255);
|
|
|
|
opts.imopts.background[2] = (unsigned char)(m_fBackground[2]*255);
|
|
|
|
|
|
|
|
if (SystemDoDialog(LC_DLG_PICTURE_SAVE, &opts))
|
|
|
|
{
|
|
|
|
if (m_bAnimation)
|
|
|
|
opts.to = min(opts.to, m_nTotalFrames);
|
|
|
|
else
|
|
|
|
opts.to = min(opts.to, 255);
|
|
|
|
opts.from = max(1, opts.from);
|
|
|
|
|
|
|
|
if (opts.multiple)
|
|
|
|
{
|
|
|
|
if (opts.from > opts.to)
|
|
|
|
{
|
|
|
|
unsigned short t = opts.from;
|
|
|
|
opts.from = opts.to;
|
|
|
|
opts.to = t;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
opts.from = opts.to = m_bAnimation ? m_nCurFrame : m_nCurStep;
|
|
|
|
|
|
|
|
Image* images = new Image[opts.to-opts.from+1];
|
|
|
|
CreateImages (images, opts.width, opts.height, opts.from, opts.to, false);
|
|
|
|
|
|
|
|
char *ptr, ext[4];
|
|
|
|
ptr = strrchr(opts.filename, '.');
|
|
|
|
if (ptr != NULL)
|
|
|
|
{
|
|
|
|
strncpy(ext, ptr+1, 3);
|
|
|
|
strlwr(ext);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (strcmp(ext, "avi") == 0)
|
|
|
|
{
|
|
|
|
SaveVideo(opts.filename, images, opts.to-opts.from+1, m_bAnimation ? m_nFPS : 60.0f/opts.imopts.pause);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
for (int i = 0; i <= opts.to-opts.from; i++)
|
|
|
|
{
|
|
|
|
char filename[LC_MAXPATH];
|
|
|
|
if (opts.multiple)
|
|
|
|
{
|
|
|
|
char* ext = strrchr(opts.filename, '.');
|
|
|
|
*ext = 0;
|
|
|
|
sprintf(filename, "%s%02d.%s", opts.filename, i+1, ext+1);
|
|
|
|
*ext = '.';
|
|
|
|
}
|
|
|
|
else
|
|
|
|
strcpy(filename, opts.filename);
|
|
|
|
|
|
|
|
images[i].FileSave (filename, &opts.imopts);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
delete []images;
|
|
|
|
}
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case LC_FILE_3DS:
|
|
|
|
{
|
|
|
|
#ifdef LC_WINDOWS
|
|
|
|
Export3DStudio();
|
|
|
|
#endif
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case LC_FILE_HTML:
|
|
|
|
{
|
|
|
|
LC_HTMLDLG_OPTS opts;
|
|
|
|
|
|
|
|
strcpy (opts.path, Sys_ProfileLoadString ("Default", "HTML Path", ""));
|
|
|
|
if (strlen (opts.path) == 0)
|
|
|
|
{
|
|
|
|
strcpy (opts.path, m_strPathName);
|
|
|
|
if (strlen(opts.path) > 0)
|
|
|
|
{
|
|
|
|
char* ptr = strrchr(opts.path, '/');
|
|
|
|
if (ptr == NULL)
|
|
|
|
ptr = strrchr(opts.path, '\\');
|
|
|
|
if (ptr)
|
|
|
|
{
|
|
|
|
ptr++;
|
|
|
|
*ptr = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned long image = Sys_ProfileLoadInt ("Default", "HTML Image Options", 1|LC_IMAGE_TRANSPARENT);
|
|
|
|
opts.imdlg.imopts.background[0] = (unsigned char)(m_fBackground[0]*255);
|
|
|
|
opts.imdlg.imopts.background[1] = (unsigned char)(m_fBackground[1]*255);
|
|
|
|
opts.imdlg.imopts.background[2] = (unsigned char)(m_fBackground[2]*255);
|
|
|
|
opts.imdlg.from = 1;
|
|
|
|
opts.imdlg.to = 1;
|
|
|
|
opts.imdlg.multiple = false;
|
|
|
|
opts.imdlg.width = Sys_ProfileLoadInt ("Default", "HTML Image Width", 256);
|
|
|
|
opts.imdlg.height = Sys_ProfileLoadInt ("Default", "HTML Image Height", 160);
|
|
|
|
opts.imdlg.imopts.quality = Sys_ProfileLoadInt ("Default", "JPEG Quality", 70);
|
|
|
|
opts.imdlg.imopts.interlaced = (image & LC_IMAGE_PROGRESSIVE) != 0;
|
|
|
|
opts.imdlg.imopts.transparent = (image & LC_IMAGE_TRANSPARENT) != 0;
|
|
|
|
opts.imdlg.imopts.truecolor = (image & LC_IMAGE_HIGHCOLOR) != 0;
|
|
|
|
opts.imdlg.imopts.pause = 1;
|
|
|
|
opts.imdlg.imopts.format = (unsigned char)(image & ~(LC_IMAGE_MASK));
|
|
|
|
|
|
|
|
unsigned long ul = Sys_ProfileLoadInt ("Default", "HTML Options", LC_HTML_SINGLEPAGE);
|
|
|
|
opts.singlepage = (ul & LC_HTML_SINGLEPAGE) != 0;
|
|
|
|
opts.index = (ul & LC_HTML_INDEX) != 0;
|
|
|
|
opts.images = (ul & LC_HTML_IMAGES) != 0;
|
|
|
|
opts.listend = (ul & LC_HTML_LISTEND) != 0;
|
|
|
|
opts.liststep = (ul & LC_HTML_LISTSTEP) != 0;
|
|
|
|
opts.highlight = (ul & LC_HTML_HIGHLIGHT) != 0;
|
|
|
|
opts.htmlext = (ul & LC_HTML_HTMLEXT) != 0;
|
|
|
|
|
|
|
|
if (SystemDoDialog(LC_DLG_HTML, &opts))
|
|
|
|
{
|
|
|
|
FILE* f;
|
|
|
|
const char *ext, *htmlext;
|
|
|
|
char fn[LC_MAXPATH];
|
|
|
|
int i;
|
|
|
|
unsigned short last = GetLastStep();
|
|
|
|
|
|
|
|
// Save HTML options
|
|
|
|
ul = 0;
|
|
|
|
if (opts.singlepage) ul |= LC_HTML_SINGLEPAGE;
|
|
|
|
if (opts.index) ul |= LC_HTML_INDEX;
|
|
|
|
if (opts.images) ul |= LC_HTML_IMAGES;
|
|
|
|
if (opts.listend) ul |= LC_HTML_LISTEND;
|
|
|
|
if (opts.liststep) ul |= LC_HTML_LISTSTEP;
|
|
|
|
if (opts.highlight) ul |= LC_HTML_HIGHLIGHT;
|
|
|
|
if (opts.htmlext) ul |= LC_HTML_HTMLEXT;
|
|
|
|
Sys_ProfileSaveInt ("Default", "HTML Options", ul);
|
|
|
|
|
|
|
|
// Save image options
|
|
|
|
ul = opts.imdlg.imopts.format;
|
|
|
|
if (opts.imdlg.imopts.interlaced)
|
|
|
|
ul |= LC_IMAGE_PROGRESSIVE;
|
|
|
|
if (opts.imdlg.imopts.transparent)
|
|
|
|
ul |= LC_IMAGE_TRANSPARENT;
|
|
|
|
if (opts.imdlg.imopts.truecolor)
|
|
|
|
ul |= LC_IMAGE_HIGHCOLOR;
|
|
|
|
Sys_ProfileSaveInt ("Default", "HTML Image Options", ul);
|
|
|
|
Sys_ProfileSaveInt ("Default", "HTML Image Width", opts.imdlg.width);
|
|
|
|
Sys_ProfileSaveInt ("Default", "HTML Image Height", opts.imdlg.height);
|
|
|
|
|
|
|
|
switch (opts.imdlg.imopts.format)
|
|
|
|
{
|
|
|
|
case LC_IMAGE_BMP: ext = ".bmp"; break;
|
|
|
|
default:
|
|
|
|
case LC_IMAGE_GIF: ext = ".gif"; break;
|
|
|
|
case LC_IMAGE_JPG: ext = ".jpg"; break;
|
|
|
|
case LC_IMAGE_PNG: ext = ".png"; break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (opts.htmlext)
|
|
|
|
htmlext = ".html";
|
|
|
|
else
|
|
|
|
htmlext = ".htm";
|
|
|
|
|
|
|
|
i = strlen (opts.path);
|
|
|
|
if (i && opts.path[i] != '/' && opts.path[i] != '\\')
|
|
|
|
strcat (opts.path, "/");
|
|
|
|
Sys_ProfileSaveString ("Default", "HTML Path", opts.path);
|
|
|
|
|
|
|
|
/*
|
|
|
|
// Create destination folder
|
|
|
|
char *MyPath = strdup(dlg.m_strFolder);
|
|
|
|
char *p = MyPath;
|
|
|
|
int psave;
|
|
|
|
while(*p)
|
|
|
|
{
|
|
|
|
while(*p && *p != '\\')
|
|
|
|
++p;
|
|
|
|
|
|
|
|
psave = *p;
|
|
|
|
if (*p == '\\')
|
|
|
|
*p = 0;
|
|
|
|
|
|
|
|
if (strlen(MyPath) > 3)
|
|
|
|
CreateDirectory(MyPath, NULL);
|
|
|
|
|
|
|
|
*p = psave;
|
|
|
|
if (*p)
|
|
|
|
++p;
|
|
|
|
}
|
|
|
|
free(MyPath);
|
|
|
|
*/
|
|
|
|
main_window->BeginWait ();
|
|
|
|
|
|
|
|
if (opts.singlepage)
|
|
|
|
{
|
|
|
|
strcpy (fn, opts.path);
|
|
|
|
strcat (fn, m_strTitle);
|
|
|
|
strcat (fn, htmlext);
|
|
|
|
f = fopen (fn, "wt");
|
|
|
|
fprintf (f, "<HTML>\n<HEAD>\n<TITLE>Instructions for %s</TITLE>\n</HEAD>\n<BR>\n<CENTER>\n", m_strTitle);
|
|
|
|
|
|
|
|
for (i = 1; i <= last; i++)
|
|
|
|
{
|
|
|
|
fprintf(f, "<IMG SRC=\"%s-%02d%s\" ALT=\"Step %02d\" WIDTH=%d HEIGHT=%d><BR><BR>\n",
|
|
|
|
m_strTitle, i, ext, i, opts.imdlg.width, opts.imdlg.height);
|
|
|
|
|
|
|
|
if (opts.liststep)
|
|
|
|
CreateHTMLPieceList(f, i, opts.images, ext);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (opts.listend)
|
|
|
|
CreateHTMLPieceList(f, 0, opts.images, ext);
|
|
|
|
|
|
|
|
fputs("</CENTER>\n<BR><HR><BR><B><I>Created by <A HREF=\"http://www.leocad.org\">LeoCAD</A></B></I><BR></HTML>\n", f);
|
|
|
|
fclose(f);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (opts.index)
|
|
|
|
{
|
|
|
|
strcpy (fn, opts.path);
|
|
|
|
strcat (fn, m_strTitle);
|
|
|
|
strcat (fn, "-index");
|
|
|
|
strcat (fn, htmlext);
|
|
|
|
f = fopen (fn, "wt");
|
|
|
|
|
|
|
|
fprintf(f, "<HTML>\n<HEAD>\n<TITLE>Instructions for %s</TITLE>\n</HEAD>\n<BR>\n<CENTER>\n", m_strTitle);
|
|
|
|
|
|
|
|
for (i = 1; i <= last; i++)
|
|
|
|
fprintf(f, "<A HREF=\"%s-%02d%s\">Step %d<BR>\n</A>", m_strTitle, i, htmlext, i);
|
|
|
|
|
|
|
|
if (opts.listend)
|
|
|
|
fprintf(f, "<A HREF=\"%s-pieces%s\">Pieces Used</A><BR>\n", m_strTitle, htmlext);
|
|
|
|
|
|
|
|
fputs("</CENTER>\n<BR><HR><BR><B><I>Created by <A HREF=\"http://www.leocad.org\">LeoCAD</A></B></I><BR></HTML>\n", f);
|
|
|
|
fclose(f);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Create each step
|
|
|
|
for (i = 1; i <= last; i++)
|
|
|
|
{
|
|
|
|
sprintf(fn, "%s%s-%02d%s", opts.path, m_strTitle, i, htmlext);
|
|
|
|
f = fopen(fn, "wt");
|
|
|
|
|
|
|
|
fprintf(f, "<HTML>\n<HEAD>\n<TITLE>%s - Step %02d</TITLE>\n</HEAD>\n<BR>\n<CENTER>\n", m_strTitle, i);
|
|
|
|
fprintf(f, "<IMG SRC=\"%s-%02d%s\" ALT=\"Step %02d\" WIDTH=%d HEIGHT=%d><BR><BR>\n",
|
|
|
|
m_strTitle, i, ext, i, opts.imdlg.width, opts.imdlg.height);
|
|
|
|
|
|
|
|
if (opts.liststep)
|
|
|
|
CreateHTMLPieceList(f, i, opts.images, ext);
|
|
|
|
|
|
|
|
fputs("</CENTER>\n<BR><HR><BR>", f);
|
|
|
|
if (i != 1)
|
|
|
|
fprintf(f, "<A HREF=\"%s-%02d%s\">Previous</A> ", m_strTitle, i-1, htmlext);
|
|
|
|
|
|
|
|
if (opts.index)
|
|
|
|
fprintf(f, "<A HREF=\"%s-index%s\">Index</A> ", m_strTitle, htmlext);
|
|
|
|
|
|
|
|
if (i != last)
|
|
|
|
fprintf(f, "<A HREF=\"%s-%02d%s\">Next</A>", m_strTitle, i+1, htmlext);
|
|
|
|
else
|
|
|
|
if (opts.listend)
|
|
|
|
fprintf(f, "<A HREF=\"%s-pieces%s\">Pieces Used</A>", m_strTitle, htmlext);
|
|
|
|
|
|
|
|
fputs("<BR></HTML>\n",f);
|
|
|
|
fclose(f);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (opts.listend)
|
|
|
|
{
|
|
|
|
strcpy (fn, opts.path);
|
|
|
|
strcat (fn, m_strTitle);
|
|
|
|
strcat (fn, "-pieces");
|
|
|
|
strcat (fn, htmlext);
|
|
|
|
f = fopen (fn, "wt");
|
|
|
|
fprintf (f, "<HTML>\n<HEAD>\n<TITLE>Pieces used by %s</TITLE>\n</HEAD>\n<BR>\n<CENTER>\n", m_strTitle);
|
|
|
|
|
|
|
|
CreateHTMLPieceList(f, 0, opts.images, ext);
|
|
|
|
|
|
|
|
fputs("</CENTER>\n<BR><HR><BR>", f);
|
|
|
|
fprintf(f, "<A HREF=\"%s-%02d%s\">Previous</A> ", m_strTitle, i-1, htmlext);
|
|
|
|
|
|
|
|
if (opts.index)
|
|
|
|
fprintf(f, "<A HREF=\"%s-index%s\">Index</A> ", m_strTitle, htmlext);
|
|
|
|
|
|
|
|
fputs("<BR></HTML>\n",f);
|
|
|
|
fclose(f);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Save step pictures
|
|
|
|
Image* images = new Image[last];
|
|
|
|
CreateImages (images, opts.imdlg.width, opts.imdlg.height, 1, last, opts.highlight);
|
|
|
|
|
|
|
|
for (i = 0; i < last; i++)
|
|
|
|
{
|
|
|
|
sprintf(fn, "%s%s-%02d%s", opts.path, m_strTitle, i+1, ext);
|
|
|
|
images[i].FileSave (fn, &opts.imdlg.imopts);
|
|
|
|
}
|
|
|
|
delete []images;
|
|
|
|
|
|
|
|
if (opts.images)
|
|
|
|
{
|
|
|
|
int cx = 120, cy = 100;
|
|
|
|
void* render = Sys_StartMemoryRender (cx, cy);
|
|
|
|
|
|
|
|
float aspect = (float)cx/(float)cy;
|
|
|
|
glViewport(0, 0, cx, cy);
|
|
|
|
|
|
|
|
Piece *p1, *p2;
|
|
|
|
PieceInfo* pInfo;
|
|
|
|
for (p1 = m_pPieces; p1; p1 = p1->m_pNext)
|
|
|
|
{
|
|
|
|
bool bSkip = false;
|
|
|
|
pInfo = p1->GetPieceInfo();
|
|
|
|
|
|
|
|
for (p2 = m_pPieces; p2; p2 = p2->m_pNext)
|
|
|
|
{
|
|
|
|
if (p2 == p1)
|
|
|
|
break;
|
|
|
|
|
|
|
|
if (p2->GetPieceInfo() == pInfo)
|
|
|
|
{
|
|
|
|
bSkip = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (bSkip)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
glMatrixMode(GL_PROJECTION);
|
|
|
|
glLoadIdentity();
|
|
|
|
gluPerspective(30.0f, aspect, 1.0f, 50.0f);
|
|
|
|
glMatrixMode(GL_MODELVIEW);
|
|
|
|
glLoadIdentity();
|
|
|
|
glDepthFunc(GL_LEQUAL);
|
|
|
|
glClearColor(1,1,1,1);
|
|
|
|
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
|
|
|
glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE);
|
|
|
|
glEnable(GL_COLOR_MATERIAL);
|
|
|
|
glDisable (GL_DITHER);
|
|
|
|
glShadeModel(GL_FLAT);
|
|
|
|
pInfo->ZoomExtents(30.0f, aspect);
|
|
|
|
|
|
|
|
float pos[4] = { 0, 0, 10, 0 };
|
|
|
|
glLightfv(GL_LIGHT0, GL_POSITION, pos);
|
|
|
|
glEnable(GL_LIGHTING);
|
|
|
|
glEnable(GL_LIGHT0);
|
|
|
|
glEnable(GL_DEPTH_TEST);
|
|
|
|
pInfo->RenderPiece(m_nCurColor);
|
|
|
|
glFinish();
|
|
|
|
|
|
|
|
Image image;
|
|
|
|
image.FromOpenGL (cx, cy);
|
|
|
|
|
|
|
|
sprintf(fn, "%s%s%s", opts.path, pInfo->m_strName, ext);
|
|
|
|
image.FileSave (fn, &opts.imdlg.imopts);
|
|
|
|
}
|
|
|
|
Sys_FinishMemoryRender (render);
|
|
|
|
}
|
|
|
|
main_window->EndWait ();
|
|
|
|
}
|
|
|
|
} break;
|
|
|
|
|
|
|
|
// Export to POV-Ray, swap X & Y from our cs to work with LGEO.
|
|
|
|
case LC_FILE_POVRAY:
|
|
|
|
{
|
|
|
|
LC_POVRAYDLG_OPTS opts;
|
|
|
|
if (!SystemDoDialog(LC_DLG_POVRAY, &opts))
|
|
|
|
break;
|
|
|
|
|
|
|
|
// CWaitCursor wc;
|
|
|
|
char fn[LC_MAXPATH], tmp[10], *ptr;
|
|
|
|
unsigned long u;
|
|
|
|
PieceInfo* pInfo;
|
|
|
|
Piece* pPiece;
|
|
|
|
FILE* f;
|
|
|
|
char *conv = (char*)malloc (9*lcGetPiecesLibrary()->GetPieceCount ());
|
|
|
|
char *flags = (char*)malloc (lcGetPiecesLibrary()->GetPieceCount ());
|
|
|
|
memset (conv, 0, 9*lcGetPiecesLibrary()->GetPieceCount());
|
|
|
|
memset (flags, 0, lcGetPiecesLibrary()->GetPieceCount());
|
|
|
|
|
|
|
|
// read LGEO conversion table
|
|
|
|
if (strlen (opts.libpath))
|
|
|
|
{
|
|
|
|
strcpy (fn, opts.libpath);
|
|
|
|
strcat (fn, "l2p_elmt.tab");
|
|
|
|
f = fopen(fn, "rb");
|
|
|
|
|
|
|
|
if (f == NULL)
|
|
|
|
{
|
|
|
|
free (conv);
|
|
|
|
free (flags);
|
|
|
|
SystemDoMessageBox("Could not find LGEO.", LC_MB_OK|LC_MB_ICONERROR);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned char bt[4];
|
|
|
|
while (fread (&bt, 4, 1, f))
|
|
|
|
{
|
|
|
|
u = (((unsigned char)(bt[3])|((unsigned short)(bt[2]) << 8))|
|
|
|
|
(((unsigned long)(bt[1])) << 16)) + bt[0] * 16581375;
|
|
|
|
sprintf(tmp, "%d", (int)u);
|
|
|
|
pInfo = lcGetPiecesLibrary()->FindPieceInfo(tmp);
|
|
|
|
|
|
|
|
fread(&tmp, 9, 1, f);
|
|
|
|
if (tmp[8] != 0)
|
|
|
|
fread(&tmp[9], 1, 1, f);
|
|
|
|
|
|
|
|
if (pInfo != NULL)
|
|
|
|
{
|
|
|
|
int idx = lcGetPiecesLibrary()->GetPieceIndex (pInfo);
|
|
|
|
memcpy (&conv[idx*9], &tmp[1], 9);
|
|
|
|
flags[idx] = tmp[0];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
fclose (f);
|
|
|
|
|
|
|
|
strcpy(fn, opts.libpath);
|
|
|
|
strcat(fn, "l2p_ptrn.tab");
|
|
|
|
f = fopen(fn, "rb");
|
|
|
|
|
|
|
|
if (f == NULL)
|
|
|
|
{
|
|
|
|
SystemDoMessageBox("Could not find LGEO.", LC_MB_OK|LC_MB_ICONERROR);
|
|
|
|
free (conv);
|
|
|
|
free (flags);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
u = 0;
|
|
|
|
do
|
|
|
|
{
|
|
|
|
if ((tmp[u] == 0) && (u != 0))
|
|
|
|
{
|
|
|
|
u = 0;
|
|
|
|
pInfo = lcGetPiecesLibrary()->FindPieceInfo(tmp);
|
|
|
|
fread(&tmp, 8, 1, f);
|
|
|
|
|
|
|
|
if (pInfo != NULL)
|
|
|
|
{
|
|
|
|
int idx = lcGetPiecesLibrary()->GetPieceIndex (pInfo);
|
|
|
|
memcpy(&conv[idx*9], tmp, 9);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
u++;
|
|
|
|
}
|
|
|
|
while (fread(&tmp[u], 1, 1, f));
|
|
|
|
fclose(f);
|
|
|
|
}
|
|
|
|
|
|
|
|
strcpy(fn, opts.outpath);
|
|
|
|
if ((ptr = strrchr (fn, '.')))
|
|
|
|
*ptr = 0;
|
|
|
|
strcat (fn, ".inc");
|
|
|
|
f = fopen(fn, "wt");
|
|
|
|
|
|
|
|
if (!f)
|
|
|
|
{
|
|
|
|
SystemDoMessageBox("Could not open file for writing.", LC_MB_OK|LC_MB_ICONERROR);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
fputs("// Stuff that doesn't need to be changed\n\n", f);
|
|
|
|
|
|
|
|
if (strlen(opts.libpath))
|
|
|
|
fputs("#include \"lg_color.inc\"\n#include \"lg_defs.inc\"\n\n", f);
|
|
|
|
|
|
|
|
// Add include files
|
|
|
|
for (pPiece = m_pPieces; pPiece; pPiece = pPiece->m_pNext)
|
|
|
|
{
|
|
|
|
Piece* pNext;
|
|
|
|
|
|
|
|
for (pNext = m_pPieces; pNext; pNext = pNext->m_pNext)
|
|
|
|
{
|
|
|
|
pInfo = pNext->GetPieceInfo();
|
|
|
|
|
|
|
|
if (pNext == pPiece)
|
|
|
|
{
|
|
|
|
int idx = lcGetPiecesLibrary()->GetPieceIndex (pInfo);
|
|
|
|
char pat[] = "patterns/";
|
|
|
|
if (conv[idx*9+1] != 'p')
|
|
|
|
strcpy(pat, "");
|
|
|
|
|
|
|
|
if (conv[idx*9] != 0)
|
|
|
|
fprintf(f, "#include \"%s%s.inc\"\n", pat, &conv[idx*9]);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (pInfo == pPiece->GetPieceInfo())
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
const char* lg_colors[28] = { "red", "Orange", "green", "mint", "blue", "LightBlue", "yellow",
|
|
|
|
"white", "dark_grey", "black", "brown", "pink", "purple", "gold_chrome", "clear_red",
|
|
|
|
"clear_neon_orange", "clear_green", "clear_neon_yellow", "clear_blue", "clear_cyan",
|
|
|
|
"clear_yellow", "clear", "grey", "tan", "LightBrown", "rose", "Turquoise", "chrome" };
|
|
|
|
|
|
|
|
const float mycol[4][4] = { { 1.0f, 0.5f, 0.2f, 1 }, { 0.2f, 0.4f, 0.9f, 5 },
|
|
|
|
{ 0.6f, 0.4f, 0.4f, 24 }, { 0.1f, 0.7f, 0.8f, 26 }};
|
|
|
|
|
|
|
|
if (strlen(opts.libpath))
|
|
|
|
{
|
|
|
|
for (u = 0; u < 4; u++)
|
|
|
|
fprintf(f, "\n#declare lg_%s = texture {\n pigment { rgb <%.2f, %.2f, %.2f> }\n finish {\n ambient 0.1\n phong 0.3\n phong_size 20\n }\n}\n",
|
|
|
|
altcolornames[(int)mycol[u][3]], mycol[u][0], mycol[u][1], mycol[u][2]);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
fputs("#include \"colors.inc\"\n\n", f);
|
|
|
|
|
|
|
|
for (u = 0; u < LC_MAXCOLORS; u++)
|
|
|
|
fprintf(f, "\n#declare lg_%s = texture {\n pigment { rgbf <%.2f, %.2f, %.2f, %.2f> }\n finish {\n ambient 0.1\n phong 0.3\n phong_size 20\n }\n}\n",
|
|
|
|
lg_colors[u], (float)ColorArray[u][0]/255, (float)ColorArray[u][1]/255, (float)ColorArray[u][2]/255, ((ColorArray[u][3] == 255) ? 0.0f : 0.9f));
|
|
|
|
}
|
|
|
|
|
|
|
|
// if not in lgeo, create it
|
|
|
|
fputs("\n// The next objects (if any) were generated by LeoCAD.\n\n", f);
|
|
|
|
for (pPiece = m_pPieces; pPiece; pPiece = pPiece->m_pNext)
|
|
|
|
{
|
|
|
|
pInfo = pPiece->GetPieceInfo();
|
|
|
|
int idx = lcGetPiecesLibrary()->GetPieceIndex (pInfo);
|
|
|
|
if (conv[idx*9] != 0)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
for (Piece* pNext = m_pPieces; pNext; pNext = pNext->m_pNext)
|
|
|
|
{
|
|
|
|
if (pNext == pPiece)
|
|
|
|
{
|
|
|
|
char name[20];
|
|
|
|
strcpy(name, pInfo->m_strName);
|
|
|
|
while ((ptr = strchr(name, '-')))
|
|
|
|
*ptr = '_';
|
|
|
|
fprintf(f, "#declare lc_%s = union {\n", name);
|
|
|
|
|
|
|
|
unsigned short g;
|
|
|
|
for (g = 0; g < pInfo->m_nGroupCount; g++)
|
|
|
|
if (pInfo->m_nFlags & LC_PIECE_LONGDATA)
|
|
|
|
{
|
|
|
|
unsigned long* info = (unsigned long*)pInfo->m_pGroups[g].drawinfo;
|
|
|
|
unsigned long count, curcolor, colors = *info;
|
|
|
|
info++;
|
|
|
|
|
|
|
|
while (colors--)
|
|
|
|
{
|
|
|
|
curcolor = *info;
|
|
|
|
info++;
|
|
|
|
|
|
|
|
// skip if color only have lines
|
|
|
|
if ((*info == 0) && (info[1] == 0))
|
|
|
|
{
|
|
|
|
info += 2;
|
|
|
|
info += *info + 1;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
fputs(" mesh {\n", f);
|
|
|
|
|
|
|
|
for (count = *info, info++; count; count -= 4)
|
|
|
|
{
|
|
|
|
fprintf(f, " triangle { <%.2f, %.2f, %.2f>, <%.2f, %.2f, %.2f>, <%.2f, %.2f, %.2f> }\n",
|
|
|
|
-pInfo->m_fVertexArray[info[0]*3+1], -pInfo->m_fVertexArray[info[0]*3], pInfo->m_fVertexArray[info[0]*3+2],
|
|
|
|
-pInfo->m_fVertexArray[info[1]*3+1], -pInfo->m_fVertexArray[info[1]*3], pInfo->m_fVertexArray[info[1]*3+2],
|
|
|
|
-pInfo->m_fVertexArray[info[2]*3+1], -pInfo->m_fVertexArray[info[2]*3], pInfo->m_fVertexArray[info[2]*3+2]);
|
|
|
|
fprintf(f, " triangle { <%.2f, %.2f, %.2f>, <%.2f, %.2f, %.2f>, <%.2f, %.2f, %.2f> }\n",
|
|
|
|
-pInfo->m_fVertexArray[info[2]*3+1], -pInfo->m_fVertexArray[info[2]*3], pInfo->m_fVertexArray[info[2]*3+2],
|
|
|
|
-pInfo->m_fVertexArray[info[3]*3+1], -pInfo->m_fVertexArray[info[3]*3], pInfo->m_fVertexArray[info[3]*3+2],
|
|
|
|
-pInfo->m_fVertexArray[info[0]*3+1], -pInfo->m_fVertexArray[info[0]*3], pInfo->m_fVertexArray[info[0]*3+2]);
|
|
|
|
info += 4;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (count = *info, info++; count; count -= 3)
|
|
|
|
{
|
|
|
|
fprintf(f, " triangle { <%.2f, %.2f, %.2f>, <%.2f, %.2f, %.2f>, <%.2f, %.2f, %.2f> }\n",
|
|
|
|
-pInfo->m_fVertexArray[info[0]*3+1], -pInfo->m_fVertexArray[info[0]*3], pInfo->m_fVertexArray[info[0]*3+2],
|
|
|
|
-pInfo->m_fVertexArray[info[1]*3+1], -pInfo->m_fVertexArray[info[1]*3], pInfo->m_fVertexArray[info[1]*3+2],
|
|
|
|
-pInfo->m_fVertexArray[info[2]*3+1], -pInfo->m_fVertexArray[info[2]*3], pInfo->m_fVertexArray[info[2]*3+2]);
|
|
|
|
info += 3;
|
|
|
|
}
|
|
|
|
info += *info + 1;
|
|
|
|
|
|
|
|
if (curcolor != LC_COL_DEFAULT && curcolor != LC_COL_EDGES)
|
|
|
|
fprintf (f, " texture { lg_%s }\n", lg_colors[curcolor]);
|
|
|
|
fputs(" }\n", f);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
unsigned short* info = (unsigned short*)pInfo->m_pGroups[g].drawinfo;
|
|
|
|
unsigned short count, curcolor, colors = *info;
|
|
|
|
info++;
|
|
|
|
|
|
|
|
while (colors--)
|
|
|
|
{
|
|
|
|
curcolor = *info;
|
|
|
|
info++;
|
|
|
|
|
|
|
|
// skip if color only have lines
|
|
|
|
if ((*info == 0) && (info[1] == 0))
|
|
|
|
{
|
|
|
|
info += 2;
|
|
|
|
info += *info + 1;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
fputs(" mesh {\n", f);
|
|
|
|
|
|
|
|
for (count = *info, info++; count; count -= 4)
|
|
|
|
{
|
|
|
|
fprintf(f, " triangle { <%.2f, %.2f, %.2f>, <%.2f, %.2f, %.2f>, <%.2f, %.2f, %.2f> }\n",
|
|
|
|
-pInfo->m_fVertexArray[info[0]*3+1], -pInfo->m_fVertexArray[info[0]*3], pInfo->m_fVertexArray[info[0]*3+2],
|
|
|
|
-pInfo->m_fVertexArray[info[1]*3+1], -pInfo->m_fVertexArray[info[1]*3], pInfo->m_fVertexArray[info[1]*3+2],
|
|
|
|
-pInfo->m_fVertexArray[info[2]*3+1], -pInfo->m_fVertexArray[info[2]*3], pInfo->m_fVertexArray[info[2]*3+2]);
|
|
|
|
fprintf(f, " triangle { <%.2f, %.2f, %.2f>, <%.2f, %.2f, %.2f>, <%.2f, %.2f, %.2f> }\n",
|
|
|
|
-pInfo->m_fVertexArray[info[2]*3+1], -pInfo->m_fVertexArray[info[2]*3], pInfo->m_fVertexArray[info[2]*3+2],
|
|
|
|
-pInfo->m_fVertexArray[info[3]*3+1], -pInfo->m_fVertexArray[info[3]*3], pInfo->m_fVertexArray[info[3]*3+2],
|
|
|
|
-pInfo->m_fVertexArray[info[0]*3+1], -pInfo->m_fVertexArray[info[0]*3], pInfo->m_fVertexArray[info[0]*3+2]);
|
|
|
|
info += 4;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (count = *info, info++; count; count -= 3)
|
|
|
|
{
|
|
|
|
fprintf(f, " triangle { <%.2f, %.2f, %.2f>, <%.2f, %.2f, %.2f>, <%.2f, %.2f, %.2f> }\n",
|
|
|
|
-pInfo->m_fVertexArray[info[0]*3+1], -pInfo->m_fVertexArray[info[0]*3], pInfo->m_fVertexArray[info[0]*3+2],
|
|
|
|
-pInfo->m_fVertexArray[info[1]*3+1], -pInfo->m_fVertexArray[info[1]*3], pInfo->m_fVertexArray[info[1]*3+2],
|
|
|
|
-pInfo->m_fVertexArray[info[2]*3+1], -pInfo->m_fVertexArray[info[2]*3], pInfo->m_fVertexArray[info[2]*3+2]);
|
|
|
|
info += 3;
|
|
|
|
}
|
|
|
|
info += *info + 1;
|
|
|
|
|
|
|
|
if (curcolor != LC_COL_DEFAULT && curcolor != LC_COL_EDGES)
|
|
|
|
fprintf (f, " texture { lg_%s }\n", lg_colors[curcolor]);
|
|
|
|
fputs(" }\n", f);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fputs("}\n\n", f);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (pNext->GetPieceInfo() == pInfo)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fclose(f);
|
|
|
|
if ((ptr = strrchr (fn, '.')))
|
|
|
|
*ptr = 0;
|
|
|
|
strcat (fn, ".pov");
|
|
|
|
f = fopen(fn, "wt");
|
|
|
|
|
|
|
|
if (!f)
|
|
|
|
{
|
|
|
|
SystemDoMessageBox("Could not open file for writing.", LC_MB_OK|LC_MB_ICONERROR);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((ptr = strrchr (fn, '.')))
|
|
|
|
*ptr = 0;
|
|
|
|
ptr = strrchr (fn, '\\');
|
|
|
|
if (!ptr)
|
|
|
|
ptr = strrchr (fn, '/');
|
|
|
|
if (ptr)
|
|
|
|
ptr++;
|
|
|
|
else
|
|
|
|
ptr = fn;
|
|
|
|
|
|
|
|
fprintf(f, "// File created by LeoCAD\n//\n\n#include \"%s.inc\"\n", ptr);
|
|
|
|
float eye[3], target[3], up[3];
|
|
|
|
m_pViewCameras[m_nActiveViewport]->GetEyePos (eye);
|
|
|
|
m_pViewCameras[m_nActiveViewport]->GetTargetPos (target);
|
|
|
|
m_pViewCameras[m_nActiveViewport]->GetUpVec (up);
|
|
|
|
|
|
|
|
fprintf(f, "\ncamera {\n sky<%1g,%1g,%1g>\n location <%1g, %1g, %1g>\n look_at <%1g, %1g, %1g>\n angle %.0f\n}\n\n",
|
|
|
|
up[0], up[1], up[2], eye[1], eye[0], eye[2], target[1], target[0], target[2], m_pViewCameras[m_nActiveViewport]->m_fovy);
|
|
|
|
fprintf(f, "background { color rgb <%1g, %1g, %1g> }\n\nlight_source { <0, 0, 20> White shadowless }\n\n",
|
|
|
|
m_fBackground[0], m_fBackground[1], m_fBackground[2]);
|
|
|
|
|
|
|
|
for (pPiece = m_pPieces; pPiece; pPiece = pPiece->m_pNext)
|
|
|
|
{
|
|
|
|
float fl[12], pos[3], rot[4];
|
|
|
|
char name[20];
|
|
|
|
int idx = lcGetPiecesLibrary()->GetPieceIndex (pPiece->GetPieceInfo ());
|
|
|
|
|
|
|
|
if (conv[idx*9] == 0)
|
|
|
|
{
|
|
|
|
char* ptr;
|
|
|
|
sprintf(name, "lc_%s", pPiece->GetPieceInfo()->m_strName);
|
|
|
|
while ((ptr = strchr(name, '-')))
|
|
|
|
*ptr = '_';
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
strcpy (name, &conv[idx*9]);
|
|
|
|
if (pPiece->IsTransparent())
|
|
|
|
strcat(name, "_clear");
|
|
|
|
}
|
|
|
|
|
|
|
|
pPiece->GetPosition(pos);
|
|
|
|
pPiece->GetRotation(rot);
|
|
|
|
Matrix mat(rot, pos);
|
|
|
|
mat.ToLDraw(fl);
|
|
|
|
|
|
|
|
// Slope needs to be handled correctly
|
|
|
|
if (flags[idx] == 1)
|
|
|
|
fprintf (f, "merge {\n object {\n %s\n texture { lg_%s }\n }\n"
|
|
|
|
" object {\n %s_slope\n texture { lg_%s normal { bumps 0.3 scale 0.02 } }\n }\n"
|
|
|
|
" matrix <%.4f, %.4f, %.4f, %.4f, %.4f, %.4f, %.4f, %.4f, %.4f, %.4f, %.4f, %.4f>\n}\n",
|
|
|
|
name, lg_colors[pPiece->GetColor()], &conv[idx*9], lg_colors[pPiece->GetColor()],
|
|
|
|
-fl[11], -fl[5], fl[8], -fl[9], -fl[3], fl[6],
|
|
|
|
-fl[10], -fl[4], fl[7], pos[1], pos[0], pos[2]);
|
|
|
|
else
|
|
|
|
fprintf(f, "object {\n %s\n texture { lg_%s }\n matrix <%.4f, %.4f, %.4f, %.4f, %.4f, %.4f, %.4f, %.4f, %.4f, %.4f, %.4f, %.4f>\n}\n",
|
|
|
|
name, lg_colors[pPiece->GetColor()], -fl[11], -fl[5], fl[8], -fl[9], -fl[3], fl[6],
|
|
|
|
-fl[10], -fl[4], fl[7], pos[1], pos[0], pos[2]);
|
|
|
|
}
|
|
|
|
fclose (f);
|
|
|
|
free (conv);
|
|
|
|
free (flags);
|
|
|
|
|
|
|
|
if (opts.render)
|
|
|
|
{
|
|
|
|
#ifdef LC_WINDOWS
|
|
|
|
// TODO: Linux support
|
|
|
|
char buf[600];
|
|
|
|
char tmp[LC_MAXPATH], out[LC_MAXPATH];
|
|
|
|
sprintf(out, "%s.pov", fn);
|
|
|
|
GetShortPathName(out, out, LC_MAXPATH);
|
|
|
|
GetShortPathName(opts.libpath, tmp, LC_MAXPATH);
|
|
|
|
sprintf (buf, "+L%s +I%s", tmp, out);
|
|
|
|
ptr = strrchr (out, '\\');
|
|
|
|
if (ptr)
|
|
|
|
*(ptr+1) = 0;
|
|
|
|
ShellExecute(::GetDesktopWindow(), "open", opts.povpath, buf, out, SW_SHOWNORMAL);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case LC_FILE_WAVEFRONT:
|
|
|
|
{
|
|
|
|
char filename[LC_MAXPATH];
|
|
|
|
if (!SystemDoDialog(LC_DLG_WAVEFRONT, filename))
|
|
|
|
break;
|
|
|
|
|
|
|
|
char buf[LC_MAXPATH], *ptr;
|
|
|
|
FILE* stream = fopen(filename, "wt");
|
|
|
|
unsigned long vert = 1, i;
|
|
|
|
Piece* pPiece;
|
|
|
|
|
|
|
|
strcpy(buf, m_strPathName);
|
|
|
|
ptr = strrchr(buf, '\\');
|
|
|
|
if (ptr)
|
|
|
|
ptr++;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
ptr = strrchr(buf, '/');
|
|
|
|
if (ptr)
|
|
|
|
ptr++;
|
|
|
|
else
|
|
|
|
ptr = buf;
|
|
|
|
}
|
|
|
|
fputs("# Model exported from LeoCAD\n", stream);
|
|
|
|
if (strlen(buf) != 0)
|
|
|
|
fprintf(stream,"# Original name: %s\n", ptr);
|
|
|
|
if (strlen(m_strAuthor))
|
|
|
|
fprintf(stream, "# Author: %s\n", m_strAuthor);
|
|
|
|
|
|
|
|
strcpy(buf, filename);
|
|
|
|
ptr = strrchr(buf, '.');
|
|
|
|
if (ptr)
|
|
|
|
*ptr = 0;
|
|
|
|
|
|
|
|
strcat(buf, ".mtl");
|
|
|
|
ptr = strrchr(buf, '\\');
|
|
|
|
if (ptr)
|
|
|
|
ptr++;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
ptr = strrchr(buf, '/');
|
|
|
|
if (ptr)
|
|
|
|
ptr++;
|
|
|
|
else
|
|
|
|
ptr = buf;
|
|
|
|
}
|
|
|
|
|
|
|
|
fprintf(stream, "#\n\nmtllib %s\n\n", ptr);
|
|
|
|
|
|
|
|
FILE* mat = fopen(buf, "wt");
|
|
|
|
fputs("# Colors used by LeoCAD\n# You need to add transparency values\n#\n\n", mat);
|
|
|
|
for (i = 0; i < LC_MAXCOLORS; i++)
|
|
|
|
fprintf(mat, "newmtl %s\nKd %.2f %.2f %.2f\n\n", altcolornames[i], (float)FlatColorArray[i][0]/255, (float)FlatColorArray[i][1]/255, (float)FlatColorArray[i][2]/255);
|
|
|
|
fclose(mat);
|
|
|
|
|
|
|
|
for (pPiece = m_pPieces; pPiece; pPiece = pPiece->m_pNext)
|
|
|
|
{
|
|
|
|
float pos[3], rot[4], tmp[3];
|
|
|
|
pPiece->GetPosition(pos);
|
|
|
|
pPiece->GetRotation(rot);
|
|
|
|
Matrix mat(rot, pos);
|
|
|
|
PieceInfo* pInfo = pPiece->GetPieceInfo();
|
|
|
|
|
|
|
|
for (i = 0; i < pInfo->m_nVertexCount*3; i += 3)
|
|
|
|
{
|
|
|
|
mat.TransformPoint(tmp, &pInfo->m_fVertexArray[i]);
|
|
|
|
fprintf(stream, "v %.2f %.2f %.2f\n", tmp[0], tmp[1], tmp[2]);
|
|
|
|
}
|
|
|
|
fputs("#\n\n", stream);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (pPiece = m_pPieces; pPiece; pPiece = pPiece->m_pNext)
|
|
|
|
{
|
|
|
|
strcpy(buf, pPiece->GetName());
|
|
|
|
for (i = 0; i < strlen(buf); i++)
|
|
|
|
if ((buf[i] == '#') || (buf[i] == ' '))
|
|
|
|
buf[i] = '_';
|
|
|
|
|
|
|
|
fprintf(stream, "g %s\n", buf);
|
|
|
|
pPiece->GetPieceInfo()->WriteWavefront(stream, pPiece->GetColor(), &vert);
|
|
|
|
}
|
|
|
|
|
|
|
|
fclose(stream);
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case LC_FILE_PROPERTIES:
|
|
|
|
{
|
|
|
|
LC_PROPERTIESDLG_OPTS opts;
|
|
|
|
|
|
|
|
opts.strTitle = m_strTitle;
|
|
|
|
strcpy(opts.strAuthor, m_strAuthor);
|
|
|
|
strcpy(opts.strDescription, m_strDescription);
|
|
|
|
strcpy(opts.strComments, m_strComments);
|
|
|
|
opts.strFilename = m_strPathName;
|
|
|
|
|
|
|
|
opts.lines = lcGetPiecesLibrary()->GetPieceCount();
|
|
|
|
opts.count = (unsigned short*)malloc(lcGetPiecesLibrary()->GetPieceCount()*LC_MAXCOLORS*sizeof(unsigned short));
|
|
|
|
memset (opts.count, 0, lcGetPiecesLibrary()->GetPieceCount()*LC_MAXCOLORS*sizeof(unsigned short));
|
|
|
|
opts.names = (char**)malloc(lcGetPiecesLibrary()->GetPieceCount()*sizeof(char*));
|
|
|
|
for (int i = 0; i < lcGetPiecesLibrary()->GetPieceCount(); i++)
|
|
|
|
opts.names[i] = lcGetPiecesLibrary()->GetPieceInfo (i)->m_strDescription;
|
|
|
|
|
|
|
|
for (Piece* pPiece = m_pPieces; pPiece; pPiece = pPiece->m_pNext)
|
|
|
|
{
|
|
|
|
int idx = lcGetPiecesLibrary()->GetPieceIndex (pPiece->GetPieceInfo ());
|
|
|
|
opts.count[idx*LC_MAXCOLORS+pPiece->GetColor()]++;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (SystemDoDialog(LC_DLG_PROPERTIES, &opts))
|
|
|
|
{
|
|
|
|
if (strcmp(m_strAuthor, opts.strAuthor) ||
|
|
|
|
strcmp(m_strDescription, opts.strDescription) ||
|
|
|
|
strcmp(m_strComments, opts.strComments))
|
|
|
|
{
|
|
|
|
strcpy(m_strAuthor, opts.strAuthor);
|
|
|
|
strcpy(m_strDescription, opts.strDescription);
|
|
|
|
strcpy(m_strComments, opts.strComments);
|
|
|
|
SetModifiedFlag(true);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
free(opts.count);
|
|
|
|
free(opts.names);
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case LC_FILE_TERRAIN:
|
|
|
|
{
|
|
|
|
Terrain* temp = new Terrain();
|
|
|
|
*temp = *m_pTerrain;
|
|
|
|
|
|
|
|
if (SystemDoDialog(LC_DLG_TERRAIN, temp))
|
|
|
|
{
|
|
|
|
*m_pTerrain = *temp;
|
2011-09-20 01:03:28 +02:00
|
|
|
m_pTerrain->LoadTexture(true);
|
2011-09-07 23:06:51 +02:00
|
|
|
}
|
|
|
|
delete temp;
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case LC_FILE_LIBRARY:
|
|
|
|
{
|
|
|
|
FileMem file;
|
|
|
|
FileSave(&file, true);
|
|
|
|
|
|
|
|
if (SystemDoDialog(LC_DLG_LIBRARY, NULL))
|
|
|
|
{
|
|
|
|
if (lcGetPiecesLibrary()->m_Modified)
|
|
|
|
{
|
|
|
|
DeleteContents(true);
|
|
|
|
FileLoad(&file, true, false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case LC_FILE_RECENT:
|
|
|
|
{
|
|
|
|
OpenProject(main_window->GetMRU(nParam));
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case LC_EDIT_UNDO:
|
|
|
|
case LC_EDIT_REDO:
|
|
|
|
{
|
|
|
|
LC_UNDOINFO *pUndo, *pTmp;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
if (id == LC_EDIT_UNDO)
|
|
|
|
{
|
|
|
|
if ((m_pUndoList != NULL) && (m_pUndoList->pNext != NULL))
|
|
|
|
{
|
|
|
|
// Remove the first item from the undo list.
|
|
|
|
pUndo = m_pUndoList;
|
|
|
|
m_pUndoList = pUndo->pNext;
|
|
|
|
|
|
|
|
// Check if we need to delete the last redo info.
|
|
|
|
for (pTmp = m_pRedoList, i = 0; pTmp; pTmp = pTmp->pNext, i++)
|
|
|
|
if ((i == 29) && (pTmp->pNext != NULL))
|
|
|
|
{
|
|
|
|
delete pTmp->pNext;
|
|
|
|
pTmp->pNext = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
pUndo->pNext = m_pRedoList;
|
|
|
|
m_pRedoList = pUndo;
|
|
|
|
|
|
|
|
pUndo = m_pUndoList;
|
|
|
|
DeleteContents(true);
|
|
|
|
FileLoad(&pUndo->file, true, false);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (m_bUndoOriginal && (m_pUndoList != NULL) && (m_pUndoList->pNext == NULL))
|
|
|
|
SetModifiedFlag(false);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (m_pRedoList != NULL)
|
|
|
|
{
|
|
|
|
// Remove the first element from the redo list.
|
|
|
|
pUndo = m_pRedoList;
|
|
|
|
m_pRedoList = pUndo->pNext;
|
|
|
|
|
|
|
|
// Check if we can delete the last undo info.
|
|
|
|
for (pTmp = m_pUndoList, i = 0; pTmp; pTmp = pTmp->pNext, i++)
|
|
|
|
if ((i == 30) && (pTmp->pNext != NULL))
|
|
|
|
{
|
|
|
|
delete pTmp->pNext;
|
|
|
|
pTmp->pNext = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Add info to the start of the undo list.
|
|
|
|
pUndo->pNext = m_pUndoList;
|
|
|
|
m_pUndoList = pUndo;
|
|
|
|
|
|
|
|
// Load state.
|
|
|
|
DeleteContents(true);
|
|
|
|
FileLoad(&pUndo->file, true, false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
SystemUpdateUndoRedo(m_pUndoList->pNext ? m_pUndoList->strText : NULL, m_pRedoList ? m_pRedoList->strText : NULL);
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case LC_EDIT_CUT:
|
|
|
|
case LC_EDIT_COPY:
|
|
|
|
{
|
|
|
|
if (IsDrawing())
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (m_pClipboard[m_nCurClipboard] != NULL)
|
|
|
|
delete m_pClipboard[m_nCurClipboard];
|
|
|
|
m_pClipboard[m_nCurClipboard] = new FileMem;
|
|
|
|
|
|
|
|
int i = 0;
|
|
|
|
Piece* pPiece;
|
|
|
|
Camera* pCamera;
|
|
|
|
Group* pGroup;
|
|
|
|
// Light* pLight;
|
|
|
|
|
|
|
|
for (pPiece = m_pPieces; pPiece; pPiece = pPiece->m_pNext)
|
|
|
|
if (pPiece->IsSelected())
|
|
|
|
i++;
|
|
|
|
m_pClipboard[m_nCurClipboard]->Write(&i, sizeof(i));
|
|
|
|
|
|
|
|
for (pPiece = m_pPieces; pPiece; pPiece = pPiece->m_pNext)
|
|
|
|
if (pPiece->IsSelected())
|
|
|
|
pPiece->FileSave(*m_pClipboard[m_nCurClipboard], m_pGroups);
|
|
|
|
|
|
|
|
for (i = 0, pGroup = m_pGroups; pGroup; pGroup = pGroup->m_pNext)
|
|
|
|
i++;
|
|
|
|
m_pClipboard[m_nCurClipboard]->Write(&i, sizeof(i));
|
|
|
|
|
|
|
|
for (pGroup = m_pGroups; pGroup; pGroup = pGroup->m_pNext)
|
|
|
|
pGroup->FileSave(m_pClipboard[m_nCurClipboard], m_pGroups);
|
|
|
|
|
|
|
|
for (i = 0, pCamera = m_pCameras; pCamera; pCamera = pCamera->m_pNext)
|
|
|
|
if (pCamera->IsSelected())
|
|
|
|
i++;
|
|
|
|
m_pClipboard[m_nCurClipboard]->Write(&i, sizeof(i));
|
|
|
|
|
|
|
|
for (pCamera = m_pCameras; pCamera; pCamera = pCamera->m_pNext)
|
|
|
|
if (pCamera->IsSelected())
|
|
|
|
pCamera->FileSave(*m_pClipboard[m_nCurClipboard]);
|
|
|
|
/*
|
|
|
|
for (i = 0, pLight = m_pLights; pLight; pLight = pLight->m_pNext)
|
|
|
|
if (pLight->IsSelected())
|
|
|
|
i++;
|
|
|
|
m_pClipboard[m_nCurClipboard]->Write(&i, sizeof(i));
|
|
|
|
|
|
|
|
for (pLight = m_pLights; pLight; pLight = pLight->m_pNext)
|
|
|
|
if (pLight->IsSelected())
|
|
|
|
pLight->FileSave(m_pClipboard[m_nCurClipboard]);
|
|
|
|
*/
|
|
|
|
if (id == LC_EDIT_CUT)
|
|
|
|
{
|
|
|
|
RemoveSelectedObjects();
|
|
|
|
SystemUpdateFocus(NULL);
|
|
|
|
UpdateSelection();
|
|
|
|
UpdateAllViews ();
|
|
|
|
SetModifiedFlag(true);
|
|
|
|
CheckPoint("Cutting");
|
|
|
|
}
|
|
|
|
SystemExportClipboard(m_pClipboard[m_nCurClipboard]);
|
|
|
|
SystemUpdatePaste(true);
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case LC_EDIT_PASTE:
|
|
|
|
{
|
|
|
|
if (IsDrawing())
|
|
|
|
return;
|
|
|
|
|
|
|
|
int i, j;
|
|
|
|
Piece* pPasted = NULL;
|
|
|
|
File* file = m_pClipboard[m_nCurClipboard];
|
|
|
|
if (file == NULL)
|
|
|
|
break;
|
|
|
|
file->Seek(0, SEEK_SET);
|
|
|
|
SelectAndFocusNone(false);
|
|
|
|
|
|
|
|
file->Read(&i, sizeof(i));
|
|
|
|
while (i--)
|
|
|
|
{
|
|
|
|
char name[LC_PIECE_NAME_LEN];
|
|
|
|
Piece* pPiece = new Piece(NULL);
|
|
|
|
pPiece->FileLoad(*file, name);
|
|
|
|
PieceInfo* pInfo = lcGetPiecesLibrary()->FindPieceInfo(name);
|
|
|
|
if (pInfo)
|
|
|
|
{
|
|
|
|
pPiece->SetPieceInfo(pInfo);
|
|
|
|
pPiece->m_pNext = pPasted;
|
|
|
|
pPasted = pPiece;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
delete pPiece;
|
|
|
|
}
|
|
|
|
|
|
|
|
file->Read(&i, sizeof(i));
|
|
|
|
Piece* pPiece;
|
|
|
|
Group** groups = (Group**)malloc(i*sizeof(Group**));
|
|
|
|
for (j = 0; j < i; j++)
|
|
|
|
{
|
|
|
|
groups[j] = new Group();
|
|
|
|
groups[j]->FileLoad(file);
|
|
|
|
}
|
|
|
|
|
|
|
|
while (pPasted)
|
|
|
|
{
|
|
|
|
pPiece = pPasted;
|
|
|
|
pPasted = pPasted->m_pNext;
|
|
|
|
pPiece->CreateName(m_pPieces);
|
|
|
|
pPiece->SetFrameShow(m_nCurFrame);
|
|
|
|
pPiece->SetStepShow(m_nCurStep);
|
|
|
|
AddPiece(pPiece);
|
|
|
|
pPiece->Select(true, false, false);
|
|
|
|
|
|
|
|
j = LC_POINTER_TO_INT(pPiece->GetGroup());
|
|
|
|
if (j != -1)
|
|
|
|
pPiece->SetGroup(groups[j]);
|
|
|
|
else
|
|
|
|
pPiece->UnGroup(NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (j = 0; j < i; j++)
|
|
|
|
{
|
|
|
|
int g = LC_POINTER_TO_INT(groups[j]->m_pGroup);
|
|
|
|
groups[j]->m_pGroup = (g != -1) ? groups[g] : NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (j = 0; j < i; j++)
|
|
|
|
{
|
|
|
|
Group* pGroup;
|
|
|
|
bool add = false;
|
|
|
|
for (pPiece = m_pPieces; pPiece; pPiece = pPiece->m_pNext)
|
|
|
|
{
|
|
|
|
for (pGroup = pPiece->GetGroup(); pGroup; pGroup = pGroup->m_pGroup)
|
|
|
|
if (pGroup == groups[j])
|
|
|
|
{
|
|
|
|
add = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (add)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (add)
|
|
|
|
{
|
|
|
|
int a, max = 0;
|
|
|
|
|
|
|
|
for (pGroup = m_pGroups; pGroup; pGroup = pGroup->m_pNext)
|
|
|
|
if (strncmp("Pasted Group #", pGroup->m_strName, 14) == 0)
|
|
|
|
if (sscanf(pGroup->m_strName + 14, "%d", &a) == 1)
|
|
|
|
if (a > max)
|
|
|
|
max = a;
|
|
|
|
|
|
|
|
sprintf(groups[j]->m_strName, "Pasted Group #%.2d", max+1);
|
|
|
|
groups[j]->m_pNext = m_pGroups;
|
|
|
|
m_pGroups = groups[j];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
delete groups[j];
|
|
|
|
}
|
|
|
|
|
|
|
|
free(groups);
|
|
|
|
|
|
|
|
Camera* pCamera = m_pCameras;
|
|
|
|
while (pCamera->m_pNext)
|
|
|
|
pCamera = pCamera->m_pNext;
|
|
|
|
file->Read(&i, sizeof(i));
|
|
|
|
|
|
|
|
while (i--)
|
|
|
|
{
|
|
|
|
pCamera = new Camera(8, pCamera);
|
|
|
|
pCamera->FileLoad(*file);
|
|
|
|
pCamera->Select(true, false, false);
|
|
|
|
pCamera->GetTarget ()->Select(true, false, false);
|
|
|
|
}
|
|
|
|
|
|
|
|
// TODO: lights
|
|
|
|
CalculateStep();
|
|
|
|
SetModifiedFlag(true);
|
|
|
|
CheckPoint("Pasting");
|
|
|
|
SystemUpdateFocus(NULL);
|
|
|
|
UpdateSelection();
|
|
|
|
UpdateAllViews ();
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case LC_EDIT_SELECT_ALL:
|
|
|
|
{
|
|
|
|
Piece* pPiece;
|
|
|
|
for (pPiece = m_pPieces; pPiece; pPiece = pPiece->m_pNext)
|
|
|
|
if (pPiece->IsVisible(m_bAnimation ? m_nCurFrame : m_nCurStep, m_bAnimation))
|
|
|
|
pPiece->Select(true, false, false);
|
|
|
|
|
|
|
|
// pFrame->UpdateInfo();
|
|
|
|
UpdateSelection();
|
|
|
|
UpdateAllViews ();
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case LC_EDIT_SELECT_NONE:
|
|
|
|
{
|
|
|
|
SelectAndFocusNone(false);
|
|
|
|
messenger->Dispatch (LC_MSG_FOCUS_CHANGED, NULL);
|
|
|
|
UpdateSelection();
|
|
|
|
UpdateAllViews();
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case LC_EDIT_SELECT_INVERT:
|
|
|
|
{
|
|
|
|
Piece* pPiece;
|
|
|
|
for (pPiece = m_pPieces; pPiece; pPiece = pPiece->m_pNext)
|
|
|
|
if (pPiece->IsVisible(m_bAnimation ? m_nCurFrame : m_nCurStep, m_bAnimation))
|
|
|
|
{
|
|
|
|
if (pPiece->IsSelected())
|
|
|
|
pPiece->Select(false, false, false);
|
|
|
|
else
|
|
|
|
pPiece->Select(true, false, false);
|
|
|
|
}
|
|
|
|
|
|
|
|
messenger->Dispatch (LC_MSG_FOCUS_CHANGED, NULL);
|
|
|
|
UpdateSelection();
|
|
|
|
UpdateAllViews();
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case LC_EDIT_SELECT_BYNAME:
|
|
|
|
{
|
|
|
|
Piece* pPiece;
|
|
|
|
Camera* pCamera;
|
|
|
|
Light* pLight;
|
|
|
|
Group* pGroup;
|
|
|
|
int i = 0;
|
|
|
|
|
|
|
|
for (pPiece = m_pPieces; pPiece; pPiece = pPiece->m_pNext)
|
|
|
|
if (pPiece->IsVisible(m_bAnimation ? m_nCurFrame : m_nCurStep, m_bAnimation))
|
|
|
|
i++;
|
|
|
|
|
|
|
|
for (pCamera = m_pCameras; pCamera; pCamera = pCamera->m_pNext)
|
|
|
|
if (pCamera != m_pViewCameras[m_nActiveViewport])
|
|
|
|
if (pCamera->IsVisible())
|
|
|
|
i++;
|
|
|
|
|
|
|
|
for (pLight = m_pLights; pLight; pLight = pLight->m_pNext)
|
|
|
|
if (pLight->IsVisible())
|
|
|
|
i++;
|
|
|
|
|
|
|
|
// TODO: add only groups with visible pieces
|
|
|
|
for (pGroup = m_pGroups; pGroup; pGroup = pGroup->m_pNext)
|
|
|
|
i++;
|
|
|
|
|
|
|
|
if (i == 0)
|
|
|
|
{
|
|
|
|
// TODO: say 'Nothing to select'
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
LC_SEL_DATA* opts = (LC_SEL_DATA*)malloc((i+1)*sizeof(LC_SEL_DATA));
|
|
|
|
i = 0;
|
|
|
|
|
|
|
|
for (pPiece = m_pPieces; pPiece; pPiece = pPiece->m_pNext)
|
|
|
|
if (pPiece->IsVisible(m_bAnimation ? m_nCurFrame : m_nCurStep, m_bAnimation))
|
|
|
|
{
|
|
|
|
opts[i].name = pPiece->GetName();
|
|
|
|
opts[i].type = LC_SELDLG_PIECE;
|
|
|
|
opts[i].selected = pPiece->IsSelected();
|
|
|
|
opts[i].pointer = pPiece;
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (pCamera = m_pCameras; pCamera; pCamera = pCamera->m_pNext)
|
|
|
|
if (pCamera != m_pViewCameras[m_nActiveViewport])
|
|
|
|
if (pCamera->IsVisible())
|
|
|
|
{
|
|
|
|
opts[i].name = pCamera->GetName();
|
|
|
|
opts[i].type = LC_SELDLG_CAMERA;
|
|
|
|
opts[i].selected = pCamera->IsSelected();
|
|
|
|
opts[i].pointer = pCamera;
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (pLight = m_pLights; pLight; pLight = pLight->m_pNext)
|
|
|
|
if (pLight->IsVisible())
|
|
|
|
{
|
|
|
|
opts[i].name = pLight->GetName();
|
|
|
|
opts[i].type = LC_SELDLG_LIGHT;
|
|
|
|
opts[i].selected = pLight->IsSelected();
|
|
|
|
opts[i].pointer = pLight;
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
|
|
|
|
// TODO: add only groups with visible pieces
|
|
|
|
for (pGroup = m_pGroups; pGroup; pGroup = pGroup->m_pNext)
|
|
|
|
{
|
|
|
|
opts[i].name = pGroup->m_strName;
|
|
|
|
opts[i].type = LC_SELDLG_GROUP;
|
|
|
|
// TODO: check if selected
|
|
|
|
opts[i].selected = false;
|
|
|
|
opts[i].pointer = pGroup;
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
opts[i].pointer = NULL;
|
|
|
|
|
|
|
|
if (SystemDoDialog(LC_DLG_SELECTBYNAME, opts))
|
|
|
|
{
|
|
|
|
SelectAndFocusNone(false);
|
|
|
|
|
|
|
|
for (i = 0; opts[i].pointer != NULL; i++)
|
|
|
|
{
|
|
|
|
if (!opts[i].selected)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
switch (opts[i].type)
|
|
|
|
{
|
|
|
|
case LC_SELDLG_PIECE:
|
|
|
|
{
|
|
|
|
((Piece*)opts[i].pointer)->Select(true, false, false);
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case LC_SELDLG_CAMERA:
|
|
|
|
{
|
|
|
|
((Camera*)opts[i].pointer)->Select(true, false, false);
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case LC_SELDLG_LIGHT:
|
|
|
|
{
|
|
|
|
((Light*)opts[i].pointer)->Select(true, false, false);
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case LC_SELDLG_GROUP:
|
|
|
|
{
|
|
|
|
pGroup = (Group*)opts[i].pointer;
|
|
|
|
pGroup = pGroup->GetTopGroup();
|
|
|
|
for (pPiece = m_pPieces; pPiece; pPiece = pPiece->m_pNext)
|
|
|
|
if (pPiece->GetTopGroup() == pGroup)
|
|
|
|
pPiece->Select(true, false, false);
|
|
|
|
} break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
UpdateSelection();
|
|
|
|
UpdateAllViews();
|
|
|
|
// pFrame->UpdateInfo();
|
|
|
|
}
|
|
|
|
|
|
|
|
free(opts);
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case LC_PIECE_INSERT:
|
|
|
|
{
|
|
|
|
if (m_pCurPiece == NULL)
|
|
|
|
break;
|
|
|
|
Piece* pLast = NULL;
|
|
|
|
Piece* pPiece = new Piece(m_pCurPiece);
|
|
|
|
|
|
|
|
for (pLast = m_pPieces; pLast; pLast = pLast->m_pNext)
|
|
|
|
if ((pLast->IsFocused()) || (pLast->m_pNext == NULL))
|
|
|
|
break;
|
|
|
|
|
|
|
|
if (pLast != NULL)
|
|
|
|
{
|
|
|
|
Vector3 Pos;
|
|
|
|
Vector4 Rot;
|
|
|
|
|
|
|
|
GetPieceInsertPosition(pLast, Pos, Rot);
|
|
|
|
|
|
|
|
pPiece->Initialize(Pos[0], Pos[1], Pos[2], m_nCurStep, m_nCurFrame, m_nCurColor);
|
|
|
|
|
|
|
|
pPiece->ChangeKey(m_nCurStep, false, false, Rot, LC_PK_ROTATION);
|
|
|
|
pPiece->ChangeKey(m_nCurFrame, true, false, Rot, LC_PK_ROTATION);
|
|
|
|
pPiece->UpdatePosition(m_bAnimation ? m_nCurFrame : m_nCurStep, m_bAnimation);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
pPiece->Initialize(0, 0, 0, m_nCurStep, m_nCurFrame, m_nCurColor);
|
|
|
|
|
|
|
|
SelectAndFocusNone(false);
|
|
|
|
pPiece->CreateName(m_pPieces);
|
|
|
|
AddPiece(pPiece);
|
|
|
|
pPiece->CalculateConnections(m_pConnections, m_bAnimation ? m_nCurFrame : m_nCurStep, m_bAnimation, true, true);
|
|
|
|
pPiece->Select (true, true, false);
|
|
|
|
messenger->Dispatch (LC_MSG_FOCUS_CHANGED, pPiece);
|
|
|
|
UpdateSelection();
|
|
|
|
SystemPieceComboAdd(m_pCurPiece->m_strDescription);
|
|
|
|
|
|
|
|
if (m_nSnap & LC_DRAW_MOVE)
|
|
|
|
SetAction(LC_ACTION_MOVE);
|
|
|
|
|
|
|
|
// AfxGetMainWnd()->PostMessage(WM_LC_UPDATE_INFO, (WPARAM)pNew, OT_PIECE);
|
|
|
|
UpdateAllViews();
|
|
|
|
SetModifiedFlag(true);
|
|
|
|
CheckPoint("Inserting");
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case LC_PIECE_DELETE:
|
|
|
|
{
|
|
|
|
if (RemoveSelectedObjects())
|
|
|
|
{
|
|
|
|
messenger->Dispatch (LC_MSG_FOCUS_CHANGED, NULL);
|
|
|
|
UpdateSelection();
|
|
|
|
UpdateAllViews();
|
|
|
|
SetModifiedFlag(true);
|
|
|
|
CheckPoint("Deleting");
|
|
|
|
}
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case LC_PIECE_MINIFIG:
|
|
|
|
{
|
|
|
|
MinifigWizard *wiz = new MinifigWizard (m_ViewList[0]);
|
|
|
|
int i;
|
|
|
|
|
|
|
|
wiz->IncRef ();
|
|
|
|
|
|
|
|
if (SystemDoDialog (LC_DLG_MINIFIG, wiz))
|
|
|
|
{
|
|
|
|
SelectAndFocusNone(false);
|
|
|
|
|
|
|
|
for (i = 0; i < LC_MFW_NUMITEMS; i++)
|
|
|
|
{
|
|
|
|
if (wiz->m_Info[i] == NULL)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
Matrix mat;
|
|
|
|
Piece* pPiece = new Piece(wiz->m_Info[i]);
|
|
|
|
|
|
|
|
Vector4& Position = wiz->m_Matrices[i][3];
|
|
|
|
Vector4 Rotation = wiz->m_Matrices[i].ToAxisAngle();
|
|
|
|
Rotation[3] *= LC_RTOD;
|
|
|
|
pPiece->Initialize(Position[0], Position[1], Position[2], m_nCurStep, m_nCurFrame, wiz->m_Colors[i]);
|
|
|
|
pPiece->CreateName(m_pPieces);
|
|
|
|
AddPiece(pPiece);
|
|
|
|
pPiece->Select(true, false, false);
|
|
|
|
|
|
|
|
pPiece->ChangeKey(1, false, false, Rotation, LC_PK_ROTATION);
|
|
|
|
pPiece->ChangeKey(1, true, false, Rotation, LC_PK_ROTATION);
|
|
|
|
pPiece->UpdatePosition(m_bAnimation ? m_nCurFrame : m_nCurStep, m_bAnimation);
|
|
|
|
pPiece->CalculateConnections(m_pConnections, m_bAnimation ? m_nCurFrame : m_nCurStep, m_bAnimation, false, true);
|
|
|
|
|
|
|
|
SystemPieceComboAdd(wiz->m_Info[i]->m_strDescription);
|
|
|
|
}
|
|
|
|
|
|
|
|
float bs[6] = { 10000, 10000, 10000, -10000, -10000, -10000 };
|
|
|
|
int max = 0;
|
|
|
|
|
|
|
|
Group* pGroup;
|
|
|
|
for (pGroup = m_pGroups; pGroup; pGroup = pGroup->m_pNext)
|
|
|
|
if (strncmp (pGroup->m_strName, "Minifig #", 9) == 0)
|
|
|
|
if (sscanf(pGroup->m_strName, "Minifig #%d", &i) == 1)
|
|
|
|
if (i > max)
|
|
|
|
max = i;
|
|
|
|
pGroup = new Group;
|
|
|
|
sprintf(pGroup->m_strName, "Minifig #%.2d", max+1);
|
|
|
|
|
|
|
|
pGroup->m_pNext = m_pGroups;
|
|
|
|
m_pGroups = pGroup;
|
|
|
|
|
|
|
|
for (Piece* pPiece = m_pPieces; pPiece; pPiece = pPiece->m_pNext)
|
|
|
|
if (pPiece->IsSelected())
|
|
|
|
{
|
|
|
|
pPiece->SetGroup(pGroup);
|
|
|
|
pPiece->CompareBoundingBox(bs);
|
|
|
|
}
|
|
|
|
|
|
|
|
pGroup->m_fCenter[0] = (bs[0]+bs[3])/2;
|
|
|
|
pGroup->m_fCenter[1] = (bs[1]+bs[4])/2;
|
|
|
|
pGroup->m_fCenter[2] = (bs[2]+bs[5])/2;
|
|
|
|
|
|
|
|
messenger->Dispatch (LC_MSG_FOCUS_CHANGED, NULL);
|
|
|
|
UpdateSelection();
|
|
|
|
UpdateAllViews();
|
|
|
|
SetModifiedFlag(true);
|
|
|
|
CheckPoint("Minifig");
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < LC_MFW_NUMITEMS; i++)
|
|
|
|
if (wiz->m_Info[i])
|
|
|
|
wiz->m_Info[i]->DeRef();
|
|
|
|
|
|
|
|
wiz->DecRef ();
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case LC_PIECE_ARRAY:
|
|
|
|
{
|
|
|
|
LC_ARRAYDLG_OPTS opts;
|
|
|
|
|
|
|
|
if (SystemDoDialog(LC_DLG_ARRAY, &opts))
|
|
|
|
{
|
|
|
|
int total;
|
|
|
|
|
|
|
|
total = opts.n1DCount;
|
|
|
|
if (opts.nArrayDimension > 0)
|
|
|
|
total *= opts.n2DCount;
|
|
|
|
if (opts.nArrayDimension > 1)
|
|
|
|
total *= opts.n3DCount;
|
|
|
|
|
|
|
|
if (total < 2)
|
|
|
|
{
|
|
|
|
SystemDoMessageBox("Array only have 1 element.", LC_MB_OK|LC_MB_ICONWARNING);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((m_nSnap & LC_DRAW_CM_UNITS) == 0)
|
|
|
|
{
|
|
|
|
opts.f2D[0] *= 0.08f;
|
|
|
|
opts.f2D[1] *= 0.08f;
|
|
|
|
opts.f2D[2] *= 0.08f;
|
|
|
|
opts.f3D[0] *= 0.08f;
|
|
|
|
opts.f3D[1] *= 0.08f;
|
|
|
|
opts.f3D[2] *= 0.08f;
|
|
|
|
opts.fMove[0] *= 0.08f;
|
|
|
|
opts.fMove[1] *= 0.08f;
|
|
|
|
opts.fMove[2] *= 0.08f;
|
|
|
|
}
|
|
|
|
|
|
|
|
Piece *pPiece, *pFirst = NULL, *pLast = NULL;
|
|
|
|
float bs[6] = { 10000, 10000, 10000, -10000, -10000, -10000 };
|
|
|
|
int sel = 0;
|
|
|
|
unsigned long i, j, k;
|
|
|
|
|
|
|
|
for (pPiece = m_pPieces; pPiece; pPiece = pPiece->m_pNext)
|
|
|
|
if (pPiece->IsSelected())
|
|
|
|
{
|
|
|
|
pPiece->CompareBoundingBox(bs);
|
|
|
|
sel++;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (pPiece = m_pPieces; pPiece; pPiece = pPiece->m_pNext)
|
|
|
|
{
|
|
|
|
if (!pPiece->IsSelected())
|
|
|
|
continue;
|
|
|
|
|
|
|
|
for (i = 0; i < opts.n1DCount; i++)
|
|
|
|
{
|
|
|
|
float pos[3], param[4];
|
|
|
|
pPiece->GetRotation(param);
|
|
|
|
pPiece->GetPosition(pos);
|
|
|
|
Matrix mat(param, pos);
|
|
|
|
|
|
|
|
if (sel == 1)
|
|
|
|
{
|
|
|
|
mat.GetTranslation(pos);
|
|
|
|
mat.Rotate(i*opts.fRotate[0], 1, 0, 0);
|
|
|
|
mat.Rotate(i*opts.fRotate[1], 0, 1, 0);
|
|
|
|
mat.Rotate(i*opts.fRotate[2], 0, 0, 1);
|
|
|
|
mat.SetTranslation(pos);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
mat.RotateCenter(i*opts.fRotate[0],1,0,0,(bs[0]+bs[3])/2,(bs[1]+bs[4])/2,(bs[2]+bs[5])/2);
|
|
|
|
mat.RotateCenter(i*opts.fRotate[1],0,1,0,(bs[0]+bs[3])/2,(bs[1]+bs[4])/2,(bs[2]+bs[5])/2);
|
|
|
|
mat.RotateCenter(i*opts.fRotate[2],0,0,1,(bs[0]+bs[3])/2,(bs[1]+bs[4])/2,(bs[2]+bs[5])/2);
|
|
|
|
}
|
|
|
|
mat.ToAxisAngle(param);
|
|
|
|
mat.GetTranslation(pos);
|
|
|
|
|
|
|
|
if (i != 0)
|
|
|
|
{
|
|
|
|
if (pLast)
|
|
|
|
{
|
|
|
|
pLast->m_pNext = new Piece(pPiece->GetPieceInfo());
|
|
|
|
pLast = pLast->m_pNext;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
pLast = pFirst = new Piece(pPiece->GetPieceInfo());
|
|
|
|
|
|
|
|
pLast->Initialize(pos[0]+i*opts.fMove[0], pos[1]+i*opts.fMove[1], pos[2]+i*opts.fMove[2],
|
|
|
|
m_nCurStep, m_nCurFrame, pPiece->GetColor());
|
|
|
|
pLast->ChangeKey(1, false, false, param, LC_PK_ROTATION);
|
|
|
|
pLast->ChangeKey(1, true, false, param, LC_PK_ROTATION);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (opts.nArrayDimension == 0)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
for (j = 0; j < opts.n2DCount; j++)
|
|
|
|
{
|
|
|
|
if (j != 0)
|
|
|
|
{
|
|
|
|
if (pLast)
|
|
|
|
{
|
|
|
|
pLast->m_pNext = new Piece(pPiece->GetPieceInfo());
|
|
|
|
pLast = pLast->m_pNext;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
pLast = pFirst = new Piece(pPiece->GetPieceInfo());
|
|
|
|
|
|
|
|
pLast->Initialize(pos[0]+i*opts.fMove[0]+j*opts.f2D[0], pos[1]+i*opts.fMove[1]+j*opts.f2D[1], pos[2]+i*opts.fMove[2]+j*opts.f2D[2],
|
|
|
|
m_nCurStep, m_nCurFrame, pPiece->GetColor());
|
|
|
|
pLast->ChangeKey(1, false, false, param, LC_PK_ROTATION);
|
|
|
|
pLast->ChangeKey(1, true, false, param, LC_PK_ROTATION);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (opts.nArrayDimension == 1)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
for (k = 1; k < opts.n3DCount; k++)
|
|
|
|
{
|
|
|
|
if (pLast)
|
|
|
|
{
|
|
|
|
pLast->m_pNext = new Piece(pPiece->GetPieceInfo());
|
|
|
|
pLast = pLast->m_pNext;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
pLast = pFirst = new Piece(pPiece->GetPieceInfo());
|
|
|
|
|
|
|
|
pLast->Initialize(pos[0]+i*opts.fMove[0]+j*opts.f2D[0]+k*opts.f3D[0], pos[1]+i*opts.fMove[1]+j*opts.f2D[1]+k*opts.f3D[1], pos[2]+i*opts.fMove[2]+j*opts.f2D[2]+k*opts.f3D[2],
|
|
|
|
m_nCurStep, m_nCurFrame, pPiece->GetColor());
|
|
|
|
pLast->ChangeKey(1, false, false, param, LC_PK_ROTATION);
|
|
|
|
pLast->ChangeKey(1, true, false, param, LC_PK_ROTATION);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
while (pFirst)
|
|
|
|
{
|
|
|
|
pPiece = pFirst->m_pNext;
|
|
|
|
pFirst->CreateName(m_pPieces);
|
|
|
|
pFirst->UpdatePosition(m_bAnimation ? m_nCurFrame : m_nCurStep, m_bAnimation);
|
|
|
|
AddPiece(pFirst);
|
|
|
|
pFirst->CalculateConnections(m_pConnections, m_bAnimation ? m_nCurFrame : m_nCurStep, m_bAnimation, false, true);
|
|
|
|
pFirst = pPiece;
|
|
|
|
}
|
|
|
|
|
|
|
|
SelectAndFocusNone(true);
|
|
|
|
// SystemUpdateFocus(NULL);
|
|
|
|
UpdateSelection();
|
|
|
|
UpdateAllViews();
|
|
|
|
SetModifiedFlag(true);
|
|
|
|
CheckPoint("Array");
|
|
|
|
}
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case LC_PIECE_COPYKEYS:
|
|
|
|
{
|
|
|
|
float move[3], rot[4];
|
|
|
|
Piece* pPiece;
|
|
|
|
|
|
|
|
for (pPiece = m_pPieces; pPiece; pPiece = pPiece->m_pNext)
|
|
|
|
if (pPiece->IsSelected())
|
|
|
|
{
|
|
|
|
pPiece->CalculateSingleKey (m_bAnimation ? m_nCurStep : m_nCurFrame, !m_bAnimation, LC_PK_POSITION, move);
|
|
|
|
pPiece->CalculateSingleKey (m_bAnimation ? m_nCurStep : m_nCurFrame, !m_bAnimation, LC_PK_ROTATION, rot);
|
|
|
|
pPiece->ChangeKey(m_bAnimation ? m_nCurFrame : m_nCurStep, m_bAnimation, m_bAddKeys, move, LC_PK_POSITION);
|
|
|
|
pPiece->ChangeKey(m_bAnimation ? m_nCurFrame : m_nCurStep, m_bAnimation, m_bAddKeys, rot, LC_PK_ROTATION);
|
|
|
|
}
|
|
|
|
|
|
|
|
// TODO: cameras and lights
|
|
|
|
|
|
|
|
CalculateStep();
|
|
|
|
UpdateAllViews();
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case LC_PIECE_GROUP:
|
|
|
|
{
|
|
|
|
Group* pGroup;
|
|
|
|
int i, max = 0;
|
|
|
|
char name[65];
|
|
|
|
|
|
|
|
for (pGroup = m_pGroups; pGroup; pGroup = pGroup->m_pNext)
|
|
|
|
if (strncmp (pGroup->m_strName, "Group #", 7) == 0)
|
|
|
|
if (sscanf(pGroup->m_strName, "Group #%d", &i) == 1)
|
|
|
|
if (i > max)
|
|
|
|
max = i;
|
|
|
|
sprintf(name, "Group #%.2d", max+1);
|
|
|
|
|
|
|
|
if (SystemDoDialog(LC_DLG_GROUP, name))
|
|
|
|
{
|
|
|
|
pGroup = new Group();
|
|
|
|
strcpy(pGroup->m_strName, name);
|
|
|
|
pGroup->m_pNext = m_pGroups;
|
|
|
|
m_pGroups = pGroup;
|
|
|
|
float bs[6] = { 10000, 10000, 10000, -10000, -10000, -10000 };
|
|
|
|
|
|
|
|
for (Piece* pPiece = m_pPieces; pPiece; pPiece = pPiece->m_pNext)
|
|
|
|
if (pPiece->IsSelected())
|
|
|
|
{
|
|
|
|
pPiece->DoGroup(pGroup);
|
|
|
|
pPiece->CompareBoundingBox(bs);
|
|
|
|
}
|
|
|
|
|
|
|
|
pGroup->m_fCenter[0] = (bs[0]+bs[3])/2;
|
|
|
|
pGroup->m_fCenter[1] = (bs[1]+bs[4])/2;
|
|
|
|
pGroup->m_fCenter[2] = (bs[2]+bs[5])/2;
|
|
|
|
|
|
|
|
RemoveEmptyGroups();
|
|
|
|
SetModifiedFlag(true);
|
|
|
|
CheckPoint("Grouping");
|
|
|
|
}
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case LC_PIECE_UNGROUP:
|
|
|
|
{
|
|
|
|
Group* pList = NULL;
|
|
|
|
Group* pGroup;
|
|
|
|
Group* tmp;
|
|
|
|
Piece* pPiece;
|
|
|
|
|
|
|
|
for (pPiece = m_pPieces; pPiece; pPiece = pPiece->m_pNext)
|
|
|
|
if (pPiece->IsSelected())
|
|
|
|
{
|
|
|
|
pGroup = pPiece->GetTopGroup();
|
|
|
|
|
|
|
|
// Check if we already removed the group
|
|
|
|
for (tmp = pList; tmp; tmp = tmp->m_pNext)
|
|
|
|
if (pGroup == tmp)
|
|
|
|
pGroup = NULL;
|
|
|
|
|
|
|
|
if (pGroup != NULL)
|
|
|
|
{
|
|
|
|
// First remove the group from the array
|
|
|
|
for (tmp = m_pGroups; tmp->m_pNext; tmp = tmp->m_pNext)
|
|
|
|
if (tmp->m_pNext == pGroup)
|
|
|
|
{
|
|
|
|
tmp->m_pNext = pGroup->m_pNext;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (pGroup == m_pGroups)
|
|
|
|
m_pGroups = pGroup->m_pNext;
|
|
|
|
|
|
|
|
// Now add it to the list of top groups
|
|
|
|
pGroup->m_pNext = pList;
|
|
|
|
pList = pGroup;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
while (pList)
|
|
|
|
{
|
|
|
|
for (pPiece = m_pPieces; pPiece; pPiece = pPiece->m_pNext)
|
|
|
|
if (pPiece->IsSelected())
|
|
|
|
pPiece->UnGroup(pList);
|
|
|
|
|
|
|
|
pGroup = pList;
|
|
|
|
pList = pList->m_pNext;
|
|
|
|
delete pGroup;
|
|
|
|
}
|
|
|
|
|
|
|
|
RemoveEmptyGroups();
|
|
|
|
SetModifiedFlag(true);
|
|
|
|
CheckPoint("Ungrouping");
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case LC_PIECE_GROUP_ADD:
|
|
|
|
{
|
|
|
|
Group* pGroup = NULL;
|
|
|
|
Piece* pPiece;
|
|
|
|
|
|
|
|
for (pPiece = m_pPieces; pPiece; pPiece = pPiece->m_pNext)
|
|
|
|
if (pPiece->IsSelected())
|
|
|
|
{
|
|
|
|
pGroup = pPiece->GetTopGroup();
|
|
|
|
if (pGroup != NULL)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (pGroup != NULL)
|
|
|
|
{
|
|
|
|
for (pPiece = m_pPieces; pPiece; pPiece = pPiece->m_pNext)
|
|
|
|
if (pPiece->IsFocused())
|
|
|
|
{
|
|
|
|
pPiece->SetGroup(pGroup);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
RemoveEmptyGroups();
|
|
|
|
SetModifiedFlag(true);
|
|
|
|
CheckPoint("Grouping");
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case LC_PIECE_GROUP_REMOVE:
|
|
|
|
{
|
|
|
|
Piece* pPiece;
|
|
|
|
|
|
|
|
for (pPiece = m_pPieces; pPiece; pPiece = pPiece->m_pNext)
|
|
|
|
if (pPiece->IsFocused())
|
|
|
|
{
|
|
|
|
pPiece->UnGroup(NULL);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
RemoveEmptyGroups();
|
|
|
|
SetModifiedFlag(true);
|
|
|
|
CheckPoint("Ungrouping");
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case LC_PIECE_GROUP_EDIT:
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
Group* pGroup;
|
|
|
|
Piece* pPiece;
|
|
|
|
LC_GROUPEDITDLG_OPTS opts;
|
|
|
|
|
|
|
|
for (i = 0, pPiece = m_pPieces; pPiece; pPiece = pPiece->m_pNext)
|
|
|
|
i++;
|
|
|
|
opts.piececount = i;
|
|
|
|
opts.pieces = (Piece**)malloc(i*sizeof(Piece*));
|
|
|
|
opts.piecesgroups = (Group**)malloc(i*sizeof(Group*));
|
|
|
|
|
|
|
|
for (i = 0, pPiece = m_pPieces; pPiece; pPiece = pPiece->m_pNext, i++)
|
|
|
|
{
|
|
|
|
opts.pieces[i] = pPiece;
|
|
|
|
opts.piecesgroups[i] = pPiece->GetGroup();
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0, pGroup = m_pGroups; pGroup; pGroup = pGroup->m_pNext)
|
|
|
|
i++;
|
|
|
|
opts.groupcount = i;
|
|
|
|
opts.groups = (Group**)malloc(i*sizeof(Group*));
|
|
|
|
opts.groupsgroups = (Group**)malloc(i*sizeof(Group*));
|
|
|
|
|
|
|
|
for (i = 0, pGroup = m_pGroups; pGroup; pGroup = pGroup->m_pNext, i++)
|
|
|
|
{
|
|
|
|
opts.groups[i] = pGroup;
|
|
|
|
opts.groupsgroups[i] = pGroup->m_pGroup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (SystemDoDialog(LC_DLG_EDITGROUPS, &opts))
|
|
|
|
{
|
|
|
|
for (i = 0; i < opts.piececount; i++)
|
|
|
|
opts.pieces[i]->SetGroup(opts.piecesgroups[i]);
|
|
|
|
|
|
|
|
for (i = 0; i < opts.groupcount; i++)
|
|
|
|
opts.groups[i]->m_pGroup = opts.groupsgroups[i];
|
|
|
|
|
|
|
|
RemoveEmptyGroups();
|
|
|
|
SelectAndFocusNone(false);
|
|
|
|
SystemUpdateFocus(NULL);
|
|
|
|
UpdateSelection();
|
|
|
|
UpdateAllViews();
|
|
|
|
SetModifiedFlag(true);
|
|
|
|
CheckPoint("Editing");
|
|
|
|
}
|
|
|
|
|
|
|
|
free(opts.pieces);
|
|
|
|
free(opts.piecesgroups);
|
|
|
|
free(opts.groups);
|
|
|
|
free(opts.groupsgroups);
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case LC_PIECE_HIDE_SELECTED:
|
|
|
|
{
|
|
|
|
Piece* pPiece;
|
|
|
|
for (pPiece = m_pPieces; pPiece; pPiece = pPiece->m_pNext)
|
|
|
|
if (pPiece->IsSelected())
|
|
|
|
pPiece->Hide();
|
|
|
|
UpdateSelection();
|
|
|
|
messenger->Dispatch (LC_MSG_FOCUS_CHANGED, NULL);
|
|
|
|
UpdateAllViews();
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case LC_PIECE_HIDE_UNSELECTED:
|
|
|
|
{
|
|
|
|
Piece* pPiece;
|
|
|
|
for (pPiece = m_pPieces; pPiece; pPiece = pPiece->m_pNext)
|
|
|
|
if (!pPiece->IsSelected())
|
|
|
|
pPiece->Hide();
|
|
|
|
UpdateSelection();
|
|
|
|
UpdateAllViews();
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case LC_PIECE_UNHIDE_ALL:
|
|
|
|
{
|
|
|
|
Piece* pPiece;
|
|
|
|
for (pPiece = m_pPieces; pPiece; pPiece = pPiece->m_pNext)
|
|
|
|
pPiece->UnHide();
|
|
|
|
UpdateSelection();
|
|
|
|
UpdateAllViews();
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case LC_PIECE_PREVIOUS:
|
|
|
|
{
|
|
|
|
bool redraw = false;
|
|
|
|
|
|
|
|
for (Piece* pPiece = m_pPieces; pPiece; pPiece = pPiece->m_pNext)
|
|
|
|
if (pPiece->IsSelected())
|
|
|
|
{
|
|
|
|
if (m_bAnimation)
|
|
|
|
{
|
|
|
|
unsigned short t = pPiece->GetFrameShow();
|
|
|
|
if (t > 1)
|
|
|
|
{
|
|
|
|
redraw = true;
|
|
|
|
pPiece->SetFrameShow(t-1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
unsigned char t = pPiece->GetStepShow();
|
|
|
|
if (t > 1)
|
|
|
|
{
|
|
|
|
redraw = true;
|
|
|
|
pPiece->SetStepShow(t-1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (redraw)
|
|
|
|
{
|
|
|
|
SetModifiedFlag(true);
|
|
|
|
CheckPoint("Modifying");
|
|
|
|
UpdateAllViews();
|
|
|
|
}
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case LC_PIECE_NEXT:
|
|
|
|
{
|
|
|
|
bool redraw = false;
|
|
|
|
|
|
|
|
for (Piece* pPiece = m_pPieces; pPiece; pPiece = pPiece->m_pNext)
|
|
|
|
if (pPiece->IsSelected())
|
|
|
|
{
|
|
|
|
if (m_bAnimation)
|
|
|
|
{
|
|
|
|
unsigned short t = pPiece->GetFrameShow();
|
|
|
|
if (t < m_nTotalFrames)
|
|
|
|
{
|
|
|
|
redraw = true;
|
|
|
|
pPiece->SetFrameShow(t+1);
|
|
|
|
|
|
|
|
if (pPiece->IsSelected () && t == m_nCurFrame)
|
|
|
|
pPiece->Select (false, false, false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
unsigned char t = pPiece->GetStepShow();
|
|
|
|
if (t < 255)
|
|
|
|
{
|
|
|
|
redraw = true;
|
|
|
|
pPiece->SetStepShow(t+1);
|
|
|
|
|
|
|
|
if (pPiece->IsSelected () && t == m_nCurStep)
|
|
|
|
pPiece->Select (false, false, false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (redraw)
|
|
|
|
{
|
|
|
|
SetModifiedFlag(true);
|
|
|
|
CheckPoint("Modifying");
|
|
|
|
UpdateAllViews();
|
|
|
|
UpdateSelection ();
|
|
|
|
}
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case LC_VIEW_PREFERENCES:
|
|
|
|
{
|
|
|
|
LC_PREFERENCESDLG_OPTS opts;
|
|
|
|
opts.nMouse = m_nMouse;
|
|
|
|
opts.nSaveInterval = m_nAutosave;
|
|
|
|
strcpy(opts.strUser, Sys_ProfileLoadString ("Default", "User", ""));
|
|
|
|
strcpy(opts.strPath, m_strModelsPath);
|
|
|
|
opts.nDetail = m_nDetail;
|
|
|
|
opts.fLineWidth = m_fLineWidth;
|
|
|
|
opts.nSnap = m_nSnap;
|
|
|
|
opts.nAngleSnap = m_nAngleSnap;
|
|
|
|
opts.nGridSize = m_nGridSize;
|
|
|
|
opts.nScene = m_nScene;
|
|
|
|
opts.fDensity = m_fFogDensity;
|
|
|
|
strcpy(opts.strBackground, m_strBackground);
|
|
|
|
memcpy(opts.fBackground, m_fBackground, sizeof(m_fBackground));
|
|
|
|
memcpy(opts.fFog, m_fFogColor, sizeof(m_fFogColor));
|
|
|
|
memcpy(opts.fAmbient, m_fAmbient, sizeof(m_fAmbient));
|
|
|
|
memcpy(opts.fGrad1, m_fGradient1, sizeof(m_fGradient1));
|
|
|
|
memcpy(opts.fGrad2, m_fGradient2, sizeof(m_fGradient2));
|
|
|
|
strcpy(opts.strFooter, m_strFooter);
|
|
|
|
strcpy(opts.strHeader, m_strHeader);
|
|
|
|
|
|
|
|
if (SystemDoDialog(LC_DLG_PREFERENCES, &opts))
|
|
|
|
{
|
|
|
|
m_nMouse = opts.nMouse;
|
|
|
|
m_nAutosave = opts.nSaveInterval;
|
|
|
|
strcpy(m_strModelsPath, opts.strPath);
|
|
|
|
Sys_ProfileSaveString ("Default", "User", opts.strUser);
|
|
|
|
m_nDetail = opts.nDetail;
|
|
|
|
m_fLineWidth = opts.fLineWidth;
|
|
|
|
m_nSnap = opts.nSnap;
|
|
|
|
m_nAngleSnap = opts.nAngleSnap;
|
|
|
|
m_nGridSize = opts.nGridSize;
|
|
|
|
m_nScene = opts.nScene;
|
|
|
|
m_fFogDensity = opts.fDensity;
|
|
|
|
strcpy(m_strBackground, opts.strBackground);
|
|
|
|
memcpy(m_fBackground, opts.fBackground, sizeof(m_fBackground));
|
|
|
|
memcpy(m_fFogColor, opts.fFog, sizeof(m_fFogColor));
|
|
|
|
memcpy(m_fAmbient, opts.fAmbient, sizeof(m_fAmbient));
|
|
|
|
memcpy(m_fGradient1, opts.fGrad1, sizeof(m_fGradient1));
|
|
|
|
memcpy(m_fGradient2, opts.fGrad2, sizeof(m_fGradient2));
|
|
|
|
strcpy(m_strFooter, opts.strFooter);
|
|
|
|
strcpy(m_strHeader, opts.strHeader);
|
|
|
|
SystemUpdateSnap(m_nSnap);
|
|
|
|
SystemUpdateSnap(m_nMoveSnap, m_nAngleSnap);
|
|
|
|
|
|
|
|
for (int i = 0; i < m_ViewList.GetSize (); i++)
|
|
|
|
{
|
|
|
|
m_ViewList[i]->MakeCurrent ();
|
|
|
|
RenderInitialize();
|
|
|
|
}
|
|
|
|
|
|
|
|
UpdateAllViews();
|
|
|
|
}
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case LC_VIEW_ZOOM:
|
|
|
|
{
|
|
|
|
m_pViewCameras[m_nActiveViewport]->DoZoom(nParam, m_nMouse, m_bAnimation ? m_nCurFrame : m_nCurStep, m_bAnimation, m_bAddKeys);
|
|
|
|
SystemUpdateFocus(NULL);
|
|
|
|
UpdateOverlayScale();
|
|
|
|
UpdateAllViews();
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case LC_VIEW_ZOOMIN:
|
|
|
|
{
|
|
|
|
m_pViewCameras[m_nActiveViewport]->DoZoom(-1, m_nMouse, m_bAnimation ? m_nCurFrame : m_nCurStep, m_bAnimation, m_bAddKeys);
|
|
|
|
SystemUpdateFocus(NULL);
|
|
|
|
UpdateOverlayScale();
|
|
|
|
UpdateAllViews();
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case LC_VIEW_ZOOMOUT:
|
|
|
|
{
|
|
|
|
m_pViewCameras[m_nActiveViewport]->DoZoom(1, m_nMouse, m_bAnimation ? m_nCurFrame : m_nCurStep, m_bAnimation, m_bAddKeys);
|
|
|
|
SystemUpdateFocus(NULL);
|
|
|
|
UpdateOverlayScale();
|
|
|
|
UpdateAllViews();
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case LC_VIEW_ZOOMEXTENTS:
|
|
|
|
{
|
|
|
|
// FIXME: rewrite using the FustrumCull function
|
|
|
|
if (m_pPieces == 0) break;
|
|
|
|
bool bControl = Sys_KeyDown (KEY_CONTROL);
|
|
|
|
|
|
|
|
GLdouble modelMatrix[16], projMatrix[16];
|
|
|
|
float up[3], eye[3], target[3];
|
|
|
|
float bs[6] = { 10000, 10000, 10000, -10000, -10000, -10000 };
|
|
|
|
GLint viewport[4], out, x, y, w, h;
|
|
|
|
|
|
|
|
for (Piece* pPiece = m_pPieces; pPiece; pPiece = pPiece->m_pNext)
|
|
|
|
if (pPiece->IsVisible(m_bAnimation ? m_nCurFrame : m_nCurStep, m_bAnimation))
|
|
|
|
pPiece->CompareBoundingBox(bs);
|
|
|
|
|
|
|
|
float v[24] = {
|
|
|
|
bs[0], bs[1], bs[5],
|
|
|
|
bs[3], bs[1], bs[5],
|
|
|
|
bs[0], bs[1], bs[2],
|
|
|
|
bs[3], bs[4], bs[5],
|
|
|
|
bs[3], bs[4], bs[2],
|
|
|
|
bs[0], bs[4], bs[2],
|
|
|
|
bs[0], bs[4], bs[5],
|
|
|
|
bs[3], bs[1], bs[2] };
|
|
|
|
|
|
|
|
for (int vp = 0; vp < viewports[m_nViewportMode].n; vp++)
|
|
|
|
{
|
|
|
|
Camera* pCam;
|
|
|
|
if (bControl)
|
|
|
|
pCam = m_pViewCameras[vp];
|
|
|
|
else
|
|
|
|
pCam = m_pViewCameras[m_nActiveViewport];
|
|
|
|
|
|
|
|
if (!bControl)
|
|
|
|
vp = m_nActiveViewport;
|
|
|
|
|
|
|
|
x = (int)(viewports[m_nViewportMode].dim[m_nActiveViewport][0] * (float)m_nViewX);
|
|
|
|
y = (int)(viewports[m_nViewportMode].dim[m_nActiveViewport][1] * (float)m_nViewY);
|
|
|
|
w = (int)(viewports[m_nViewportMode].dim[m_nActiveViewport][2] * (float)m_nViewX);
|
|
|
|
h = (int)(viewports[m_nViewportMode].dim[m_nActiveViewport][3] * (float)m_nViewY);
|
|
|
|
float ratio = (float)w/h;
|
|
|
|
|
|
|
|
glViewport(x,y,w,h);
|
|
|
|
pCam->LoadProjection(ratio);
|
|
|
|
|
|
|
|
if (!bControl)
|
|
|
|
vp = 4;
|
|
|
|
|
|
|
|
pCam->GetTargetPos (target);
|
|
|
|
pCam->GetEyePos (eye);
|
|
|
|
|
|
|
|
up[0] = (bs[0] + bs[3])/2 - target[0];
|
|
|
|
up[1] = (bs[1] + bs[4])/2 - target[1];
|
|
|
|
up[2] = (bs[2] + bs[5])/2 - target[2];
|
|
|
|
|
|
|
|
if (pCam->IsSide())
|
|
|
|
{
|
|
|
|
eye[0] += up[0];
|
|
|
|
eye[1] += up[1];
|
|
|
|
eye[2] += up[2];
|
|
|
|
}
|
|
|
|
target[0] += up[0];
|
|
|
|
target[1] += up[1];
|
|
|
|
target[2] += up[2];
|
|
|
|
|
|
|
|
pCam->GetUpVec (up);
|
|
|
|
Vector upvec(up), frontvec(eye[0]-target[0], eye[1]-target[1], eye[2]-target[2]), sidevec;
|
|
|
|
frontvec.Normalize();
|
|
|
|
sidevec.Cross(frontvec, upvec);
|
|
|
|
upvec.Cross(sidevec, frontvec);
|
|
|
|
upvec.Normalize();
|
|
|
|
upvec.ToFloat(up);
|
|
|
|
frontvec *= 0.25f;
|
|
|
|
|
|
|
|
glMatrixMode(GL_MODELVIEW);
|
|
|
|
glGetDoublev(GL_PROJECTION_MATRIX,projMatrix);
|
|
|
|
glGetIntegerv(GL_VIEWPORT,viewport);
|
|
|
|
|
|
|
|
for (out = 0; out < 10000; out++) // Zoom in
|
|
|
|
{
|
|
|
|
eye[0] -= frontvec[0];
|
|
|
|
eye[1] -= frontvec[1];
|
|
|
|
eye[2] -= frontvec[2];
|
|
|
|
glLoadIdentity();
|
|
|
|
gluLookAt(eye[0], eye[1], eye[2], target[0], target[1], target[2], up[0], up[1], up[2]);
|
|
|
|
glGetDoublev(GL_MODELVIEW_MATRIX,modelMatrix);
|
|
|
|
|
|
|
|
for (int i = 0; i < 24; i+=3)
|
|
|
|
{
|
|
|
|
double winx, winy, winz;
|
|
|
|
gluProject (v[i], v[i+1], v[i+2], modelMatrix, projMatrix, viewport, &winx, &winy, &winz);
|
|
|
|
if ((winx < viewport[0] + 1) || (winy < viewport[1] + 1) ||
|
|
|
|
(winx > viewport[0] + viewport[2] - 1) || (winy > viewport[1] + viewport[3] - 1))
|
|
|
|
{
|
|
|
|
out = 10000;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool stp = false;
|
|
|
|
for (out = 0; out < 10000 && !stp; out++) // zoom out
|
|
|
|
{
|
|
|
|
stp = true;
|
|
|
|
eye[0] += frontvec[0];
|
|
|
|
eye[1] += frontvec[1];
|
|
|
|
eye[2] += frontvec[2];
|
|
|
|
glLoadIdentity();
|
|
|
|
gluLookAt(eye[0], eye[1], eye[2], target[0], target[1], target[2], up[0], up[1], up[2]);
|
|
|
|
glGetDoublev(GL_MODELVIEW_MATRIX,modelMatrix);
|
|
|
|
|
|
|
|
for (int i = 0; i < 24; i+=3)
|
|
|
|
{
|
|
|
|
double winx, winy, winz;
|
|
|
|
gluProject (v[i], v[i+1], v[i+2], modelMatrix, projMatrix, viewport, &winx, &winy, &winz);
|
|
|
|
if ((winx < viewport[0] + 1) || (winy < viewport[1] + 1) ||
|
|
|
|
(winx > viewport[0] + viewport[2] - 1) || (winy > viewport[1] + viewport[3] - 1))
|
|
|
|
{
|
|
|
|
stp = false;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pCam->ChangeKey(m_bAnimation ? m_nCurFrame : m_nCurStep, m_bAnimation, m_bAddKeys, eye, LC_CK_EYE);
|
|
|
|
pCam->ChangeKey(m_bAnimation ? m_nCurFrame : m_nCurStep, m_bAnimation, m_bAddKeys, target, LC_CK_TARGET);
|
|
|
|
pCam->UpdatePosition(m_bAnimation ? m_nCurFrame : m_nCurStep, m_bAnimation);
|
|
|
|
}
|
|
|
|
|
|
|
|
SystemUpdateFocus(NULL);
|
|
|
|
UpdateOverlayScale();
|
|
|
|
UpdateAllViews();
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case LC_VIEW_VIEWPORTS:
|
|
|
|
{
|
|
|
|
// Safety check
|
|
|
|
if (m_nActiveViewport >= viewports[nParam].n)
|
|
|
|
{
|
|
|
|
SystemUpdateCurrentCamera(m_pViewCameras[m_nActiveViewport], m_pViewCameras[0], m_pCameras);
|
|
|
|
m_nActiveViewport = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
SystemUpdateViewport(nParam, m_nViewportMode);
|
|
|
|
m_nViewportMode = (unsigned char)nParam;
|
|
|
|
UpdateOverlayScale();
|
|
|
|
UpdateAllViews();
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case LC_VIEW_STEP_NEXT:
|
|
|
|
{
|
|
|
|
if (m_bAnimation)
|
|
|
|
m_nCurFrame++;
|
|
|
|
else
|
|
|
|
m_nCurStep++;
|
|
|
|
|
|
|
|
CalculateStep();
|
|
|
|
UpdateSelection();
|
|
|
|
SystemUpdateFocus(NULL);
|
|
|
|
UpdateAllViews();
|
|
|
|
|
|
|
|
if (m_bAnimation)
|
|
|
|
SystemUpdateTime(m_bAnimation, m_nCurFrame, m_nTotalFrames);
|
|
|
|
else
|
|
|
|
SystemUpdateTime(m_bAnimation, m_nCurStep, 255);
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case LC_VIEW_STEP_PREVIOUS:
|
|
|
|
{
|
|
|
|
if (m_bAnimation)
|
|
|
|
m_nCurFrame--;
|
|
|
|
else
|
|
|
|
m_nCurStep--;
|
|
|
|
|
|
|
|
CalculateStep();
|
|
|
|
UpdateSelection();
|
|
|
|
SystemUpdateFocus(NULL);
|
|
|
|
UpdateAllViews();
|
|
|
|
|
|
|
|
if (m_bAnimation)
|
|
|
|
SystemUpdateTime(m_bAnimation, m_nCurFrame, m_nTotalFrames);
|
|
|
|
else
|
|
|
|
SystemUpdateTime(m_bAnimation, m_nCurStep, 255);
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case LC_VIEW_STEP_FIRST:
|
|
|
|
{
|
|
|
|
if (m_bAnimation)
|
|
|
|
m_nCurFrame = 1;
|
|
|
|
else
|
|
|
|
m_nCurStep = 1;
|
|
|
|
|
|
|
|
CalculateStep();
|
|
|
|
UpdateSelection();
|
|
|
|
SystemUpdateFocus(NULL);
|
|
|
|
UpdateAllViews();
|
|
|
|
|
|
|
|
if (m_bAnimation)
|
|
|
|
SystemUpdateTime(m_bAnimation, m_nCurFrame, m_nTotalFrames);
|
|
|
|
else
|
|
|
|
SystemUpdateTime(m_bAnimation, m_nCurStep, 255);
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case LC_VIEW_STEP_LAST:
|
|
|
|
{
|
|
|
|
if (m_bAnimation)
|
|
|
|
m_nCurFrame = m_nTotalFrames;
|
|
|
|
else
|
|
|
|
m_nCurStep = GetLastStep ();
|
|
|
|
|
|
|
|
CalculateStep();
|
|
|
|
UpdateSelection();
|
|
|
|
SystemUpdateFocus(NULL);
|
|
|
|
UpdateAllViews();
|
|
|
|
|
|
|
|
if (m_bAnimation)
|
|
|
|
SystemUpdateTime(m_bAnimation, m_nCurFrame, m_nTotalFrames);
|
|
|
|
else
|
|
|
|
SystemUpdateTime(m_bAnimation, m_nCurStep, 255);
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case LC_VIEW_STEP_CHOOSE:
|
|
|
|
{
|
|
|
|
SystemDoDialog(LC_DLG_STEPCHOOSE, NULL);
|
|
|
|
if (m_bAnimation)
|
|
|
|
SystemUpdateTime(m_bAnimation, m_nCurFrame, m_nTotalFrames);
|
|
|
|
else
|
|
|
|
SystemUpdateTime(m_bAnimation, m_nCurStep, 255);
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case LC_VIEW_STEP_SET:
|
|
|
|
{
|
|
|
|
if (IsDrawing())
|
|
|
|
break;
|
|
|
|
|
|
|
|
if (m_bAnimation)
|
|
|
|
m_nCurFrame = (nParam < m_nTotalFrames) ? (unsigned short)nParam : m_nTotalFrames;
|
|
|
|
else
|
|
|
|
m_nCurStep = (nParam < 255) ? (unsigned char)nParam : 255;
|
|
|
|
|
|
|
|
CalculateStep();
|
|
|
|
UpdateSelection();
|
|
|
|
SystemUpdateFocus(NULL);
|
|
|
|
UpdateAllViews();
|
|
|
|
|
|
|
|
if (m_bAnimation)
|
|
|
|
SystemUpdateTime(m_bAnimation, m_nCurFrame, m_nTotalFrames);
|
|
|
|
else
|
|
|
|
SystemUpdateTime(m_bAnimation, m_nCurStep, 255);
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case LC_VIEW_STEP_INSERT:
|
|
|
|
{
|
|
|
|
for (Piece* pPiece = m_pPieces; pPiece; pPiece = pPiece->m_pNext)
|
|
|
|
pPiece->InsertTime (m_bAnimation ? m_nCurFrame : m_nCurStep, m_bAnimation, 1);
|
|
|
|
|
|
|
|
for (Camera* pCamera = m_pCameras; pCamera; pCamera = pCamera->m_pNext)
|
|
|
|
pCamera->InsertTime (m_bAnimation ? m_nCurFrame : m_nCurStep, m_bAnimation, 1);
|
|
|
|
|
|
|
|
for (Light* pLight = m_pLights; pLight; pLight = pLight->m_pNext)
|
|
|
|
pLight->InsertTime (m_bAnimation ? m_nCurFrame : m_nCurStep, m_bAnimation, 1);
|
|
|
|
|
|
|
|
SetModifiedFlag (true);
|
|
|
|
if (m_bAnimation)
|
|
|
|
CheckPoint ("Adding Frame");
|
|
|
|
else
|
|
|
|
CheckPoint ("Adding Step");
|
|
|
|
CalculateStep ();
|
|
|
|
UpdateAllViews ();
|
|
|
|
UpdateSelection ();
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case LC_VIEW_STEP_DELETE:
|
|
|
|
{
|
|
|
|
for (Piece* pPiece = m_pPieces; pPiece; pPiece = pPiece->m_pNext)
|
|
|
|
pPiece->RemoveTime (m_bAnimation ? m_nCurFrame : m_nCurStep, m_bAnimation, 1);
|
|
|
|
|
|
|
|
for (Camera* pCamera = m_pCameras; pCamera; pCamera = pCamera->m_pNext)
|
|
|
|
pCamera->RemoveTime (m_bAnimation ? m_nCurFrame : m_nCurStep, m_bAnimation, 1);
|
|
|
|
|
|
|
|
for (Light* pLight = m_pLights; pLight; pLight = pLight->m_pNext)
|
|
|
|
pLight->RemoveTime (m_bAnimation ? m_nCurFrame : m_nCurStep, m_bAnimation, 1);
|
|
|
|
|
|
|
|
SetModifiedFlag (true);
|
|
|
|
if (m_bAnimation)
|
|
|
|
CheckPoint ("Removing Frame");
|
|
|
|
else
|
|
|
|
CheckPoint ("Removing Step");
|
|
|
|
CalculateStep ();
|
|
|
|
UpdateAllViews ();
|
|
|
|
UpdateSelection ();
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case LC_VIEW_STOP:
|
|
|
|
{
|
|
|
|
m_bStopRender = true;
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case LC_VIEW_PLAY:
|
|
|
|
{
|
|
|
|
SelectAndFocusNone(false);
|
|
|
|
UpdateSelection();
|
|
|
|
m_bStopRender = false;
|
|
|
|
m_bRendering = true;
|
|
|
|
SystemUpdatePlay(false, true);
|
|
|
|
long time = SystemGetTicks();
|
|
|
|
unsigned short tics;
|
|
|
|
float rate = 1000.0f/m_nFPS;
|
|
|
|
|
|
|
|
while (!m_bStopRender)
|
|
|
|
{
|
|
|
|
tics = (unsigned short)(SystemGetTicks() - time);
|
|
|
|
if (tics < rate)
|
|
|
|
continue; // nothing to do
|
|
|
|
|
|
|
|
time = SystemGetTicks();
|
|
|
|
m_nCurFrame += (unsigned short)((float)tics/rate);
|
|
|
|
while (m_nCurFrame > m_nTotalFrames)
|
|
|
|
m_nCurFrame -= m_nTotalFrames;
|
|
|
|
CalculateStep();
|
|
|
|
SystemUpdateTime(true, m_nCurFrame, m_nTotalFrames);
|
|
|
|
// RenderScene((m_nDetail & LC_DET_FAST) == 0, true);
|
|
|
|
// SystemSwapBuffers();
|
|
|
|
UpdateAllViews ();
|
|
|
|
SystemPumpMessages();
|
|
|
|
}
|
|
|
|
m_bRendering = false;
|
|
|
|
SystemUpdatePlay(true, false);
|
|
|
|
SystemUpdateFocus(NULL);
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case LC_VIEW_CAMERA_FRONT:
|
|
|
|
{
|
|
|
|
HandleCommand(LC_VIEW_CAMERA_MENU, LC_CAMERA_FRONT);
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case LC_VIEW_CAMERA_BACK:
|
|
|
|
{
|
|
|
|
HandleCommand(LC_VIEW_CAMERA_MENU, LC_CAMERA_BACK);
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case LC_VIEW_CAMERA_TOP:
|
|
|
|
{
|
|
|
|
HandleCommand(LC_VIEW_CAMERA_MENU, LC_CAMERA_TOP);
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case LC_VIEW_CAMERA_BOTTOM:
|
|
|
|
{
|
|
|
|
HandleCommand(LC_VIEW_CAMERA_MENU, LC_CAMERA_UNDER);
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case LC_VIEW_CAMERA_LEFT:
|
|
|
|
{
|
|
|
|
HandleCommand(LC_VIEW_CAMERA_MENU, LC_CAMERA_LEFT);
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case LC_VIEW_CAMERA_RIGHT:
|
|
|
|
{
|
|
|
|
HandleCommand(LC_VIEW_CAMERA_MENU, LC_CAMERA_RIGHT);
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case LC_VIEW_CAMERA_MAIN:
|
|
|
|
{
|
|
|
|
HandleCommand(LC_VIEW_CAMERA_MENU, LC_CAMERA_MAIN);
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case LC_VIEW_CAMERA_MENU:
|
|
|
|
{
|
|
|
|
Camera* pCamera = m_pCameras;
|
|
|
|
|
|
|
|
while (nParam--)
|
|
|
|
pCamera = pCamera->m_pNext;
|
|
|
|
|
|
|
|
SystemUpdateCurrentCamera(m_pViewCameras[m_nActiveViewport], pCamera, m_pCameras);
|
|
|
|
m_pViewCameras[m_nActiveViewport] = pCamera;
|
|
|
|
UpdateOverlayScale();
|
|
|
|
UpdateAllViews();
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case LC_VIEW_CAMERA_RESET:
|
|
|
|
{
|
|
|
|
Camera* pCamera;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
while (m_pCameras)
|
|
|
|
{
|
|
|
|
pCamera = m_pCameras;
|
|
|
|
m_pCameras = m_pCameras->m_pNext;
|
|
|
|
delete pCamera;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (m_pCameras = pCamera = NULL, i = 0; i < 7; i++)
|
|
|
|
{
|
|
|
|
pCamera = new Camera(i, pCamera);
|
|
|
|
if (m_pCameras == NULL)
|
|
|
|
m_pCameras = pCamera;
|
|
|
|
|
|
|
|
switch (i)
|
|
|
|
{
|
|
|
|
case LC_CAMERA_MAIN: m_pViewCameras[0] = pCamera; break;
|
|
|
|
case LC_CAMERA_FRONT: m_pViewCameras[1] = pCamera; break;
|
|
|
|
case LC_CAMERA_TOP: m_pViewCameras[2] = pCamera; break;
|
|
|
|
case LC_CAMERA_RIGHT: m_pViewCameras[3] = pCamera; break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
SystemUpdateCameraMenu(m_pCameras);
|
|
|
|
SystemUpdateCurrentCamera(NULL, m_pViewCameras[m_nActiveViewport], m_pCameras);
|
|
|
|
SystemUpdateFocus(NULL);
|
|
|
|
UpdateOverlayScale();
|
|
|
|
UpdateAllViews();
|
|
|
|
SetModifiedFlag(true);
|
|
|
|
CheckPoint("Reset Cameras");
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case LC_HELP_ABOUT:
|
|
|
|
{
|
|
|
|
SystemDoDialog(LC_DLG_ABOUT, 0);
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case LC_TOOLBAR_ANIMATION:
|
|
|
|
{
|
|
|
|
m_bAnimation = !m_bAnimation;
|
|
|
|
|
|
|
|
CalculateStep();
|
|
|
|
SystemUpdateFocus(NULL);
|
|
|
|
UpdateAllViews();
|
|
|
|
|
|
|
|
SystemUpdateAnimation(m_bAnimation, m_bAddKeys);
|
|
|
|
if (m_bAnimation)
|
|
|
|
SystemUpdateTime(m_bAnimation, m_nCurFrame, m_nTotalFrames);
|
|
|
|
else
|
|
|
|
SystemUpdateTime(m_bAnimation, m_nCurStep, 255);
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case LC_TOOLBAR_ADDKEYS:
|
|
|
|
{
|
|
|
|
m_bAddKeys = !m_bAddKeys;
|
|
|
|
SystemUpdateAnimation(m_bAnimation, m_bAddKeys);
|
|
|
|
} break;
|
|
|
|
|
|
|
|
// Change snap X, Y, Z, All, None or Angle.
|
|
|
|
case LC_TOOLBAR_SNAPMENU:
|
|
|
|
{
|
|
|
|
switch (nParam)
|
|
|
|
{
|
|
|
|
case 0:
|
|
|
|
if (m_nSnap & LC_DRAW_SNAP_X)
|
|
|
|
m_nSnap &= ~LC_DRAW_SNAP_X;
|
|
|
|
else
|
|
|
|
m_nSnap |= LC_DRAW_SNAP_X;
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
if (m_nSnap & LC_DRAW_SNAP_Y)
|
|
|
|
m_nSnap &= ~LC_DRAW_SNAP_Y;
|
|
|
|
else
|
|
|
|
m_nSnap |= LC_DRAW_SNAP_Y;
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
if (m_nSnap & LC_DRAW_SNAP_Z)
|
|
|
|
m_nSnap &= ~LC_DRAW_SNAP_Z;
|
|
|
|
else
|
|
|
|
m_nSnap |= LC_DRAW_SNAP_Z;
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
if ((m_nSnap & LC_DRAW_SNAP_XYZ) == LC_DRAW_SNAP_XYZ)
|
|
|
|
m_nSnap &= ~LC_DRAW_SNAP_XYZ;
|
|
|
|
else
|
|
|
|
m_nSnap |= LC_DRAW_SNAP_XYZ;
|
|
|
|
break;
|
|
|
|
case 4:
|
|
|
|
m_nSnap &= ~LC_DRAW_SNAP_XYZ;
|
|
|
|
break;
|
|
|
|
case 5:
|
|
|
|
if (m_nSnap & LC_DRAW_SNAP_A)
|
|
|
|
m_nSnap &= ~LC_DRAW_SNAP_A;
|
|
|
|
else
|
|
|
|
m_nSnap |= LC_DRAW_SNAP_A;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
SystemUpdateSnap(m_nSnap);
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case LC_TOOLBAR_LOCKMENU:
|
|
|
|
{
|
|
|
|
switch (nParam)
|
|
|
|
{
|
|
|
|
case 0:
|
|
|
|
if (m_nSnap & LC_DRAW_LOCK_X)
|
|
|
|
m_nSnap &= ~LC_DRAW_LOCK_X;
|
|
|
|
else
|
|
|
|
m_nSnap |= LC_DRAW_LOCK_X;
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
if (m_nSnap & LC_DRAW_LOCK_Y)
|
|
|
|
m_nSnap &= ~LC_DRAW_LOCK_Y;
|
|
|
|
else
|
|
|
|
m_nSnap |= LC_DRAW_LOCK_Y;
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
if (m_nSnap & LC_DRAW_LOCK_Z)
|
|
|
|
m_nSnap &= ~LC_DRAW_LOCK_Z;
|
|
|
|
else
|
|
|
|
m_nSnap |= LC_DRAW_LOCK_Z;
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
m_nSnap &= ~LC_DRAW_LOCK_XYZ;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
SystemUpdateSnap(m_nSnap);
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case LC_TOOLBAR_FASTRENDER:
|
|
|
|
{
|
2011-09-20 01:03:28 +02:00
|
|
|
if (m_nDetail & LC_DET_FAST)
|
|
|
|
m_nDetail &= ~LC_DET_FAST;
|
2011-09-07 23:06:51 +02:00
|
|
|
else
|
2011-09-20 01:03:28 +02:00
|
|
|
m_nDetail |= LC_DET_FAST;
|
|
|
|
UpdateAllViews();
|
2011-09-07 23:06:51 +02:00
|
|
|
|
2011-09-20 01:03:28 +02:00
|
|
|
SystemUpdateRenderingMode((m_nDetail & LC_DET_FAST) != 0);
|
2011-09-07 23:06:51 +02:00
|
|
|
} break;
|
|
|
|
|
|
|
|
case LC_EDIT_MOVEXY_SNAP_0:
|
|
|
|
case LC_EDIT_MOVEXY_SNAP_1:
|
|
|
|
case LC_EDIT_MOVEXY_SNAP_2:
|
|
|
|
case LC_EDIT_MOVEXY_SNAP_3:
|
|
|
|
case LC_EDIT_MOVEXY_SNAP_4:
|
|
|
|
case LC_EDIT_MOVEXY_SNAP_5:
|
|
|
|
case LC_EDIT_MOVEXY_SNAP_6:
|
|
|
|
case LC_EDIT_MOVEXY_SNAP_7:
|
|
|
|
case LC_EDIT_MOVEXY_SNAP_8:
|
|
|
|
case LC_EDIT_MOVEXY_SNAP_9:
|
|
|
|
{
|
|
|
|
m_nMoveSnap = (id - LC_EDIT_MOVEXY_SNAP_0) | (m_nMoveSnap & ~0xff);
|
|
|
|
SystemUpdateSnap(m_nMoveSnap, m_nAngleSnap);
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case LC_EDIT_MOVEZ_SNAP_0:
|
|
|
|
case LC_EDIT_MOVEZ_SNAP_1:
|
|
|
|
case LC_EDIT_MOVEZ_SNAP_2:
|
|
|
|
case LC_EDIT_MOVEZ_SNAP_3:
|
|
|
|
case LC_EDIT_MOVEZ_SNAP_4:
|
|
|
|
case LC_EDIT_MOVEZ_SNAP_5:
|
|
|
|
case LC_EDIT_MOVEZ_SNAP_6:
|
|
|
|
case LC_EDIT_MOVEZ_SNAP_7:
|
|
|
|
case LC_EDIT_MOVEZ_SNAP_8:
|
|
|
|
case LC_EDIT_MOVEZ_SNAP_9:
|
|
|
|
{
|
|
|
|
m_nMoveSnap = (((id - LC_EDIT_MOVEZ_SNAP_0) << 8) | (m_nMoveSnap & ~0xff00));
|
|
|
|
SystemUpdateSnap(m_nMoveSnap, m_nAngleSnap);
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case LC_EDIT_ANGLE_SNAP_0:
|
|
|
|
{
|
|
|
|
m_nAngleSnap = 1;
|
|
|
|
SystemUpdateSnap(m_nMoveSnap, m_nAngleSnap);
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case LC_EDIT_ANGLE_SNAP_1:
|
|
|
|
{
|
|
|
|
m_nAngleSnap = 5;
|
|
|
|
SystemUpdateSnap(m_nMoveSnap, m_nAngleSnap);
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case LC_EDIT_ANGLE_SNAP_2:
|
|
|
|
{
|
|
|
|
m_nAngleSnap = 10;
|
|
|
|
SystemUpdateSnap(m_nMoveSnap, m_nAngleSnap);
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case LC_EDIT_ANGLE_SNAP_3:
|
|
|
|
{
|
|
|
|
m_nAngleSnap = 15;
|
|
|
|
SystemUpdateSnap(m_nMoveSnap, m_nAngleSnap);
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case LC_EDIT_ANGLE_SNAP_4:
|
|
|
|
{
|
|
|
|
m_nAngleSnap = 30;
|
|
|
|
SystemUpdateSnap(m_nMoveSnap, m_nAngleSnap);
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case LC_EDIT_ANGLE_SNAP_5:
|
|
|
|
{
|
|
|
|
m_nAngleSnap = 45;
|
|
|
|
SystemUpdateSnap(m_nMoveSnap, m_nAngleSnap);
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case LC_EDIT_ANGLE_SNAP_6:
|
|
|
|
{
|
|
|
|
m_nAngleSnap = 60;
|
|
|
|
SystemUpdateSnap(m_nMoveSnap, m_nAngleSnap);
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case LC_EDIT_ANGLE_SNAP_7:
|
|
|
|
{
|
|
|
|
m_nAngleSnap = 90;
|
|
|
|
SystemUpdateSnap(m_nMoveSnap, m_nAngleSnap);
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case LC_EDIT_ANGLE_SNAP_8:
|
|
|
|
{
|
|
|
|
m_nAngleSnap = 180;
|
|
|
|
SystemUpdateSnap(m_nMoveSnap, m_nAngleSnap);
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case LC_EDIT_ACTION_SELECT:
|
|
|
|
{
|
|
|
|
SetAction(LC_ACTION_SELECT);
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case LC_EDIT_ACTION_INSERT:
|
|
|
|
{
|
|
|
|
SetAction(LC_ACTION_INSERT);
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case LC_EDIT_ACTION_LIGHT:
|
|
|
|
{
|
|
|
|
SetAction(LC_ACTION_LIGHT);
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case LC_EDIT_ACTION_SPOTLIGHT:
|
|
|
|
{
|
|
|
|
SetAction(LC_ACTION_SPOTLIGHT);
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case LC_EDIT_ACTION_CAMERA:
|
|
|
|
{
|
|
|
|
SetAction(LC_ACTION_CAMERA);
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case LC_EDIT_ACTION_MOVE:
|
|
|
|
{
|
|
|
|
SetAction(LC_ACTION_MOVE);
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case LC_EDIT_ACTION_ROTATE:
|
|
|
|
{
|
|
|
|
SetAction(LC_ACTION_ROTATE);
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case LC_EDIT_ACTION_ERASER:
|
|
|
|
{
|
|
|
|
SetAction(LC_ACTION_ERASER);
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case LC_EDIT_ACTION_PAINT:
|
|
|
|
{
|
|
|
|
SetAction(LC_ACTION_PAINT);
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case LC_EDIT_ACTION_ZOOM:
|
|
|
|
{
|
|
|
|
SetAction(LC_ACTION_ZOOM);
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case LC_EDIT_ACTION_ZOOM_REGION:
|
|
|
|
{
|
|
|
|
SetAction(LC_ACTION_ZOOM_REGION);
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case LC_EDIT_ACTION_PAN:
|
|
|
|
{
|
|
|
|
SetAction(LC_ACTION_PAN);
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case LC_EDIT_ACTION_ROTATE_VIEW:
|
|
|
|
{
|
|
|
|
SetAction(LC_ACTION_ROTATE_VIEW);
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case LC_EDIT_ACTION_ROLL:
|
|
|
|
{
|
|
|
|
SetAction(LC_ACTION_ROLL);
|
|
|
|
} break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Project::SetAction(int nAction)
|
|
|
|
{
|
|
|
|
bool Redraw = false;
|
|
|
|
|
|
|
|
if (m_nCurAction == LC_ACTION_INSERT)
|
|
|
|
Redraw = true;
|
|
|
|
|
|
|
|
SystemUpdateAction(nAction, m_nCurAction);
|
|
|
|
m_nCurAction = nAction;
|
|
|
|
|
|
|
|
if ((m_nCurAction == LC_ACTION_MOVE) || (m_nCurAction == LC_ACTION_ROTATE) ||
|
|
|
|
(m_nCurAction == LC_ACTION_ROTATE_VIEW))
|
|
|
|
{
|
|
|
|
ActivateOverlay();
|
|
|
|
|
|
|
|
if (m_OverlayActive)
|
|
|
|
Redraw = true;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (m_OverlayActive)
|
|
|
|
{
|
|
|
|
m_OverlayActive = false;
|
|
|
|
Redraw = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Redraw)
|
|
|
|
UpdateAllViews();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Remove unused groups
|
|
|
|
void Project::RemoveEmptyGroups()
|
|
|
|
{
|
|
|
|
bool recurse = false;
|
|
|
|
Group *g1, *g2;
|
|
|
|
Piece* pPiece;
|
|
|
|
int ref;
|
|
|
|
|
|
|
|
for (g1 = m_pGroups; g1;)
|
|
|
|
{
|
|
|
|
ref = 0;
|
|
|
|
|
|
|
|
for (pPiece = m_pPieces; pPiece; pPiece = pPiece->m_pNext)
|
|
|
|
if (pPiece->GetGroup() == g1)
|
|
|
|
ref++;
|
|
|
|
|
|
|
|
for (g2 = m_pGroups; g2; g2 = g2->m_pNext)
|
|
|
|
if (g2->m_pGroup == g1)
|
|
|
|
ref++;
|
|
|
|
|
|
|
|
if (ref < 2)
|
|
|
|
{
|
|
|
|
if (ref != 0)
|
|
|
|
{
|
|
|
|
for (pPiece = m_pPieces; pPiece; pPiece = pPiece->m_pNext)
|
|
|
|
if (pPiece->GetGroup() == g1)
|
|
|
|
pPiece->SetGroup(g1->m_pGroup);
|
|
|
|
|
|
|
|
for (g2 = m_pGroups; g2; g2 = g2->m_pNext)
|
|
|
|
if (g2->m_pGroup == g1)
|
|
|
|
g2->m_pGroup = g1->m_pGroup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (g1 == m_pGroups)
|
|
|
|
{
|
|
|
|
m_pGroups = g1->m_pNext;
|
|
|
|
delete g1;
|
|
|
|
g1 = m_pGroups;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
for (g2 = m_pGroups; g2; g2 = g2->m_pNext)
|
|
|
|
if (g2->m_pNext == g1)
|
|
|
|
{
|
|
|
|
g2->m_pNext = g1->m_pNext;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
delete g1;
|
|
|
|
g1 = g2->m_pNext;
|
|
|
|
}
|
|
|
|
|
|
|
|
recurse = true;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
g1 = g1->m_pNext;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (recurse)
|
|
|
|
RemoveEmptyGroups();
|
|
|
|
}
|
|
|
|
|
|
|
|
Group* Project::AddGroup (const char* name, Group* pParent, float x, float y, float z)
|
|
|
|
{
|
|
|
|
Group *pNewGroup = new Group();
|
|
|
|
|
|
|
|
if (name == NULL)
|
|
|
|
{
|
|
|
|
int i, max = 0;
|
|
|
|
char str[65];
|
|
|
|
|
|
|
|
for (Group *pGroup = m_pGroups; pGroup; pGroup = pGroup->m_pNext)
|
|
|
|
if (strncmp (pGroup->m_strName, "Group #", 7) == 0)
|
|
|
|
if (sscanf(pGroup->m_strName, "Group #%d", &i) == 1)
|
|
|
|
if (i > max)
|
|
|
|
max = i;
|
|
|
|
sprintf (str, "Group #%.2d", max+1);
|
|
|
|
|
|
|
|
strcpy (pNewGroup->m_strName, str);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
strcpy (pNewGroup->m_strName, name);
|
|
|
|
|
|
|
|
pNewGroup->m_pNext = m_pGroups;
|
|
|
|
m_pGroups = pNewGroup;
|
|
|
|
|
|
|
|
pNewGroup->m_fCenter[0] = x;
|
|
|
|
pNewGroup->m_fCenter[1] = y;
|
|
|
|
pNewGroup->m_fCenter[2] = z;
|
|
|
|
pNewGroup->m_pGroup = pParent;
|
|
|
|
|
|
|
|
return pNewGroup;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Project::SelectAndFocusNone(bool bFocusOnly)
|
|
|
|
{
|
|
|
|
Piece* pPiece;
|
|
|
|
Camera* pCamera;
|
|
|
|
Light* pLight;
|
|
|
|
|
|
|
|
for (pPiece = m_pPieces; pPiece; pPiece = pPiece->m_pNext)
|
|
|
|
pPiece->Select (false, bFocusOnly, false);
|
|
|
|
|
|
|
|
for (pCamera = m_pCameras; pCamera; pCamera = pCamera->m_pNext)
|
|
|
|
{
|
|
|
|
pCamera->Select (false, bFocusOnly, false);
|
|
|
|
pCamera->GetTarget ()->Select (false, bFocusOnly, false);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (pLight = m_pLights; pLight; pLight = pLight->m_pNext)
|
|
|
|
{
|
|
|
|
pLight->Select (false, bFocusOnly, false);
|
|
|
|
if (pLight->GetTarget ())
|
|
|
|
pLight->GetTarget ()->Select (false, bFocusOnly, false);
|
|
|
|
}
|
|
|
|
// AfxGetMainWnd()->PostMessage(WM_LC_UPDATE_INFO, NULL, OT_PIECE);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Project::GetSelectionCenter(Vector3& Center) const
|
|
|
|
{
|
|
|
|
float bs[6] = { 10000, 10000, 10000, -10000, -10000, -10000 };
|
|
|
|
bool Selected = false;
|
|
|
|
|
|
|
|
for (Piece* pPiece = m_pPieces; pPiece; pPiece = pPiece->m_pNext)
|
|
|
|
{
|
|
|
|
if (pPiece->IsSelected())
|
|
|
|
{
|
|
|
|
pPiece->CompareBoundingBox(bs);
|
|
|
|
Selected = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Center = Vector3((bs[0] + bs[3]) * 0.5f, (bs[1] + bs[4]) * 0.5f, (bs[2] + bs[5]) * 0.5f);
|
|
|
|
|
|
|
|
return Selected;
|
|
|
|
}
|
|
|
|
|
|
|
|
Camera* Project::GetCamera(int i)
|
|
|
|
{
|
|
|
|
Camera* pCamera;
|
|
|
|
|
|
|
|
for (pCamera = m_pCameras; i-- > 0 && pCamera; pCamera = pCamera->m_pNext)
|
|
|
|
;
|
|
|
|
return pCamera;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Project::GetActiveViewportMatrices(Matrix44& ModelView, Matrix44& Projection, int Viewport[4])
|
|
|
|
{
|
|
|
|
Viewport[0] = (int)(viewports[m_nViewportMode].dim[m_nActiveViewport][0] * (float)m_nViewX);
|
|
|
|
Viewport[1] = (int)(viewports[m_nViewportMode].dim[m_nActiveViewport][1] * (float)m_nViewY);
|
|
|
|
Viewport[2] = (int)(viewports[m_nViewportMode].dim[m_nActiveViewport][2] * (float)m_nViewX);
|
|
|
|
Viewport[3] = (int)(viewports[m_nViewportMode].dim[m_nActiveViewport][3] * (float)m_nViewY);
|
|
|
|
|
|
|
|
float Aspect = (float)Viewport[2]/(float)Viewport[3];
|
|
|
|
Camera* Cam = m_pViewCameras[m_nActiveViewport];
|
|
|
|
|
|
|
|
// Build the matrices.
|
|
|
|
ModelView.CreateLookAt(Cam->GetEyePosition(), Cam->GetTargetPosition(), Cam->GetUpVector());
|
|
|
|
Projection.CreatePerspective(Cam->m_fovy, Aspect, Cam->m_zNear, Cam->m_zFar);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Project::ConvertToUserUnits(Vector3& Value) const
|
|
|
|
{
|
|
|
|
if ((m_nSnap & LC_DRAW_CM_UNITS) == 0)
|
|
|
|
Value /= 0.08f;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Project::ConvertFromUserUnits(Vector3& Value) const
|
|
|
|
{
|
|
|
|
if ((m_nSnap & LC_DRAW_CM_UNITS) == 0)
|
|
|
|
Value *= 0.08f;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Project::GetFocusPosition(Vector3& Position) const
|
|
|
|
{
|
|
|
|
Piece* pPiece;
|
|
|
|
Camera* pCamera;
|
|
|
|
float* pos = &Position[0];
|
|
|
|
|
|
|
|
for (pPiece = m_pPieces; pPiece; pPiece = pPiece->m_pNext)
|
|
|
|
if (pPiece->IsFocused())
|
|
|
|
{
|
|
|
|
pPiece->GetPosition(pos);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (pCamera = m_pCameras; pCamera; pCamera = pCamera->m_pNext)
|
|
|
|
{
|
|
|
|
if (pCamera->IsEyeFocused())
|
|
|
|
{
|
|
|
|
pCamera->GetEyePos(pos);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (pCamera->IsTargetFocused())
|
|
|
|
{
|
|
|
|
pCamera->GetTargetPos(pos);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// TODO: light
|
|
|
|
|
|
|
|
pos[0] = pos[1] = pos[2] = 0.0f;
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Returns the object that currently has focus.
|
|
|
|
Object* Project::GetFocusObject() const
|
|
|
|
{
|
|
|
|
for (Piece* pPiece = m_pPieces; pPiece; pPiece = pPiece->m_pNext)
|
|
|
|
{
|
|
|
|
if (pPiece->IsFocused())
|
|
|
|
return pPiece;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (Camera* pCamera = m_pCameras; pCamera; pCamera = pCamera->m_pNext)
|
|
|
|
{
|
|
|
|
if (pCamera->IsEyeFocused() || pCamera->IsTargetFocused())
|
|
|
|
return pCamera;
|
|
|
|
}
|
|
|
|
|
|
|
|
// TODO: light
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Find a good starting position/orientation relative to an existing piece.
|
|
|
|
void Project::GetPieceInsertPosition(Piece* OffsetPiece, Vector3& Position, Vector4& Rotation)
|
|
|
|
{
|
|
|
|
Vector3 Dist(0, 0, OffsetPiece->GetPieceInfo()->m_fDimensions[2] - m_pCurPiece->m_fDimensions[5]);
|
|
|
|
SnapVector(Dist);
|
|
|
|
|
|
|
|
float pos[3], rot[4];
|
|
|
|
OffsetPiece->GetPosition(pos);
|
|
|
|
OffsetPiece->GetRotation(rot);
|
|
|
|
|
|
|
|
Matrix mat(rot, pos);
|
|
|
|
mat.Translate(Dist[0], Dist[1], Dist[2]);
|
|
|
|
mat.GetTranslation(pos);
|
|
|
|
|
|
|
|
Position = Vector3(pos[0], pos[1], pos[2]);
|
|
|
|
Rotation = Vector4(rot[0], rot[1], rot[2], rot[3]);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Try to find a good starting position/orientation for a new piece.
|
|
|
|
void Project::GetPieceInsertPosition(int MouseX, int MouseY, Vector3& Position, Vector4& Rotation)
|
|
|
|
{
|
|
|
|
// See if the mouse is over a piece.
|
|
|
|
LC_CLICKLINE ClickLine;
|
|
|
|
FindObjectFromPoint(MouseX, MouseY, &ClickLine, true);
|
|
|
|
|
|
|
|
Piece* HitPiece = (Piece*)ClickLine.pClosest;
|
|
|
|
if (HitPiece)
|
|
|
|
{
|
|
|
|
GetPieceInsertPosition(HitPiece, Position, Rotation);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Try to hit the base grid.
|
|
|
|
int Viewport[4] =
|
|
|
|
{
|
|
|
|
(int)(viewports[m_nViewportMode].dim[m_nActiveViewport][0] * (float)m_nViewX),
|
|
|
|
(int)(viewports[m_nViewportMode].dim[m_nActiveViewport][1] * (float)m_nViewY),
|
|
|
|
(int)(viewports[m_nViewportMode].dim[m_nActiveViewport][2] * (float)m_nViewX),
|
|
|
|
(int)(viewports[m_nViewportMode].dim[m_nActiveViewport][3] * (float)m_nViewY)
|
|
|
|
};
|
|
|
|
|
|
|
|
float Aspect = (float)Viewport[2]/(float)Viewport[3];
|
|
|
|
Camera* Cam = m_pViewCameras[m_nActiveViewport];
|
|
|
|
|
|
|
|
// Build the matrices.
|
|
|
|
Matrix44 ModelView, Projection;
|
|
|
|
ModelView.CreateLookAt(Cam->GetEyePosition(), Cam->GetTargetPosition(), Cam->GetUpVector());
|
|
|
|
Projection.CreatePerspective(Cam->m_fovy, Aspect, Cam->m_zNear, Cam->m_zFar);
|
|
|
|
|
|
|
|
Vector3 ClickPoints[2] = { Vector3((float)m_nDownX, (float)m_nDownY, 0.0f), Vector3((float)m_nDownX, (float)m_nDownY, 1.0f) };
|
|
|
|
UnprojectPoints(ClickPoints, 2, ModelView, Projection, Viewport);
|
|
|
|
|
|
|
|
Vector3 Intersection;
|
|
|
|
if (LinePlaneIntersection(Intersection, ClickPoints[0], ClickPoints[1], Vector4(0, 0, 1, 0)))
|
|
|
|
{
|
|
|
|
SnapVector(Intersection);
|
|
|
|
Position = Intersection;
|
|
|
|
Rotation = Vector4(0, 0, 1, 0);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Couldn't find a good position, so just place the piece somewhere near the camera.
|
|
|
|
Position = UnprojectPoint(Vector3((float)m_nDownX, (float)m_nDownY, 0.9f), ModelView, Projection, Viewport);
|
|
|
|
Rotation = Vector4(0, 0, 1, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Project::FindObjectFromPoint(int x, int y, LC_CLICKLINE* pLine, bool PiecesOnly)
|
|
|
|
{
|
|
|
|
GLdouble px, py, pz, rx, ry, rz;
|
|
|
|
GLdouble modelMatrix[16], projMatrix[16];
|
|
|
|
GLint viewport[4];
|
|
|
|
Piece* pPiece;
|
|
|
|
Camera* pCamera;
|
|
|
|
Light* pLight;
|
|
|
|
|
|
|
|
LoadViewportProjection(m_nActiveViewport);
|
|
|
|
glGetDoublev(GL_MODELVIEW_MATRIX,modelMatrix);
|
|
|
|
glGetDoublev(GL_PROJECTION_MATRIX,projMatrix);
|
|
|
|
glGetIntegerv(GL_VIEWPORT,viewport);
|
|
|
|
|
|
|
|
// Unproject the selected point against both the front and the back clipping plane
|
|
|
|
gluUnProject(x, y, 0, modelMatrix, projMatrix, viewport, &px, &py, &pz);
|
|
|
|
gluUnProject(x, y, 1, modelMatrix, projMatrix, viewport, &rx, &ry, &rz);
|
|
|
|
|
|
|
|
pLine->a1 = (float)px;
|
|
|
|
pLine->b1 = (float)py;
|
|
|
|
pLine->c1 = (float)pz;
|
|
|
|
pLine->a2 = (float)(rx-px);
|
|
|
|
pLine->b2 = (float)(ry-py);
|
|
|
|
pLine->c2 = (float)(rz-pz);
|
|
|
|
pLine->mindist = FLT_MAX;
|
|
|
|
pLine->pClosest = NULL;
|
|
|
|
|
|
|
|
for (pPiece = m_pPieces; pPiece; pPiece = pPiece->m_pNext)
|
|
|
|
if (pPiece->IsVisible(m_bAnimation ? m_nCurFrame : m_nCurStep, m_bAnimation))
|
|
|
|
pPiece->MinIntersectDist(pLine);
|
|
|
|
|
|
|
|
if (!PiecesOnly)
|
|
|
|
{
|
|
|
|
for (pCamera = m_pCameras; pCamera; pCamera = pCamera->m_pNext)
|
|
|
|
if (pCamera != m_pViewCameras[m_nActiveViewport])
|
|
|
|
pCamera->MinIntersectDist(pLine);
|
|
|
|
|
|
|
|
for (pLight = m_pLights; pLight; pLight = pLight->m_pNext)
|
|
|
|
pLight->MinIntersectDist(pLine);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Project::FindObjectsInBox(float x1, float y1, float x2, float y2, PtrArray<Object>& Objects)
|
|
|
|
{
|
|
|
|
int Viewport[4] =
|
|
|
|
{
|
|
|
|
(int)(viewports[m_nViewportMode].dim[m_nActiveViewport][0] * (float)m_nViewX),
|
|
|
|
(int)(viewports[m_nViewportMode].dim[m_nActiveViewport][1] * (float)m_nViewY),
|
|
|
|
(int)(viewports[m_nViewportMode].dim[m_nActiveViewport][2] * (float)m_nViewX),
|
|
|
|
(int)(viewports[m_nViewportMode].dim[m_nActiveViewport][3] * (float)m_nViewY)
|
|
|
|
};
|
|
|
|
|
|
|
|
float Aspect = (float)Viewport[2]/(float)Viewport[3];
|
|
|
|
Camera* Cam = m_pViewCameras[m_nActiveViewport];
|
|
|
|
|
|
|
|
// Build the matrices.
|
|
|
|
Matrix44 ModelView, Projection;
|
|
|
|
ModelView.CreateLookAt(Cam->GetEyePosition(), Cam->GetTargetPosition(), Cam->GetUpVector());
|
|
|
|
Projection.CreatePerspective(Cam->m_fovy, Aspect, Cam->m_zNear, Cam->m_zFar);
|
|
|
|
|
|
|
|
// Find out the top-left and bottom-right corners in screen coordinates.
|
|
|
|
float Left, Top, Bottom, Right;
|
|
|
|
|
|
|
|
if (x1 < x2)
|
|
|
|
{
|
|
|
|
Left = x1;
|
|
|
|
Right = x2;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
Left = x2;
|
|
|
|
Right = x1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (y1 > y2)
|
|
|
|
{
|
|
|
|
Top = y1;
|
|
|
|
Bottom = y2;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
Top = y2;
|
|
|
|
Bottom = y1;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Unproject 6 points to world space.
|
|
|
|
Vector3 Corners[6] =
|
|
|
|
{
|
|
|
|
Vector3(Left, Top, 0), Vector3(Left, Bottom, 0), Vector3(Right, Bottom, 0),
|
|
|
|
Vector3(Right, Top, 0), Vector3(Left, Top, 1), Vector3(Right, Bottom, 1)
|
|
|
|
};
|
|
|
|
|
|
|
|
UnprojectPoints(Corners, 6, ModelView, Projection, Viewport);
|
|
|
|
|
|
|
|
// Build the box planes.
|
|
|
|
Vector4 Planes[6];
|
|
|
|
|
|
|
|
Planes[0] = Cross3(Corners[4] - Corners[0], Corners[1] - Corners[0]).Normalize(); // Left
|
|
|
|
Planes[1] = Cross3(Corners[5] - Corners[2], Corners[3] - Corners[2]).Normalize(); // Right
|
|
|
|
Planes[2] = Cross3(Corners[3] - Corners[0], Corners[4] - Corners[0]).Normalize(); // Top
|
|
|
|
Planes[3] = Cross3(Corners[1] - Corners[2], Corners[5] - Corners[2]).Normalize(); // Bottom
|
|
|
|
Planes[4] = Cross3(Corners[1] - Corners[0], Corners[3] - Corners[0]).Normalize(); // Front
|
|
|
|
Planes[5] = Cross3(Corners[1] - Corners[2], Corners[3] - Corners[2]).Normalize(); // Back
|
|
|
|
|
|
|
|
Planes[0][3] = -Dot3(Planes[0], Corners[0]);
|
|
|
|
Planes[1][3] = -Dot3(Planes[1], Corners[5]);
|
|
|
|
Planes[2][3] = -Dot3(Planes[2], Corners[0]);
|
|
|
|
Planes[3][3] = -Dot3(Planes[3], Corners[5]);
|
|
|
|
Planes[4][3] = -Dot3(Planes[4], Corners[0]);
|
|
|
|
Planes[5][3] = -Dot3(Planes[5], Corners[5]);
|
|
|
|
|
|
|
|
// Check if any objects are inside the volume.
|
|
|
|
for (Piece* piece = m_pPieces; piece != NULL; piece = piece->m_pNext)
|
|
|
|
{
|
|
|
|
if (piece->IsVisible(m_bAnimation ? m_nCurFrame : m_nCurStep, m_bAnimation))
|
|
|
|
{
|
|
|
|
if (piece->IntersectsVolume(Planes, 6))
|
|
|
|
Objects.Add(piece);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// TODO: lights and cameras.
|
|
|
|
}
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
// Mouse handling
|
|
|
|
|
|
|
|
// Returns true if point is not inside the current viewport.
|
|
|
|
bool Project::SetActiveViewport(int px, int py)
|
|
|
|
{
|
|
|
|
float x, y, w, h;
|
|
|
|
int vp;
|
|
|
|
|
|
|
|
for (vp = 0; vp < viewports[m_nViewportMode].n; vp++)
|
|
|
|
{
|
|
|
|
x = viewports[m_nViewportMode].dim[vp][0] * (float)m_nViewX;
|
|
|
|
y = viewports[m_nViewportMode].dim[vp][1] * (float)m_nViewY;
|
|
|
|
w = viewports[m_nViewportMode].dim[vp][2] * (float)m_nViewX;
|
|
|
|
h = viewports[m_nViewportMode].dim[vp][3] * (float)m_nViewY;
|
|
|
|
|
|
|
|
if (px > x && px < x + w && py > y && py < y + h)
|
|
|
|
{
|
|
|
|
if (m_nActiveViewport != vp)
|
|
|
|
{
|
|
|
|
SystemUpdateCurrentCamera(m_pViewCameras[m_nActiveViewport], m_pViewCameras[vp], m_pCameras);
|
|
|
|
m_nActiveViewport = vp;
|
|
|
|
Render(false);
|
|
|
|
// glDrawBuffer(GL_FRONT);
|
|
|
|
// RenderViewports(true);
|
|
|
|
// glDrawBuffer(GL_BACK);
|
|
|
|
UpdateAllViews();
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// We shouldn't get here...
|
|
|
|
m_nActiveViewport = 0;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Project::LoadViewportProjection(int Viewport)
|
|
|
|
{
|
|
|
|
int x, y, w, h;
|
|
|
|
float ratio;
|
|
|
|
|
|
|
|
x = (int)(viewports[m_nViewportMode].dim[Viewport][0] * (float)m_nViewX);
|
|
|
|
y = (int)(viewports[m_nViewportMode].dim[Viewport][1] * (float)m_nViewY);
|
|
|
|
w = (int)(viewports[m_nViewportMode].dim[Viewport][2] * (float)m_nViewX);
|
|
|
|
h = (int)(viewports[m_nViewportMode].dim[Viewport][3] * (float)m_nViewY);
|
|
|
|
|
|
|
|
ratio = (float)w/h;
|
|
|
|
glViewport(x, y, w, h);
|
|
|
|
m_pViewCameras[Viewport]->LoadProjection(ratio);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Returns true if the mouse was being tracked.
|
|
|
|
bool Project::StopTracking(bool bAccept)
|
|
|
|
{
|
|
|
|
if (m_nTracking == LC_TRACK_NONE)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if ((m_nTracking == LC_TRACK_START_LEFT) || (m_nTracking == LC_TRACK_START_RIGHT))
|
|
|
|
{
|
|
|
|
if (m_pTrackFile)
|
|
|
|
{
|
|
|
|
delete m_pTrackFile;
|
|
|
|
m_pTrackFile = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
m_nTracking = LC_TRACK_NONE;
|
|
|
|
SystemReleaseMouse();
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
m_bTrackCancel = true;
|
|
|
|
m_nTracking = LC_TRACK_NONE;
|
|
|
|
SystemReleaseMouse();
|
|
|
|
|
|
|
|
// Reset the mouse overlay.
|
|
|
|
if (m_OverlayActive)
|
|
|
|
{
|
|
|
|
ActivateOverlay();
|
|
|
|
UpdateAllViews();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (bAccept)
|
|
|
|
{
|
|
|
|
switch (m_nCurAction)
|
|
|
|
{
|
|
|
|
case LC_ACTION_SELECT:
|
|
|
|
{
|
|
|
|
if (((float)m_nDownX != m_fTrack[0]) && ((float)m_nDownY != m_fTrack[1]))
|
|
|
|
{
|
|
|
|
// Find objects inside the rectangle.
|
|
|
|
PtrArray<Object> Objects;
|
|
|
|
FindObjectsInBox((float)m_nDownX, (float)m_nDownY, m_fTrack[0], m_fTrack[1], Objects);
|
|
|
|
|
|
|
|
// Deselect old pieces.
|
|
|
|
bool Control = Sys_KeyDown(KEY_CONTROL);
|
|
|
|
SelectAndFocusNone(Control);
|
|
|
|
|
|
|
|
// Select new pieces.
|
|
|
|
for (int i = 0; i < Objects.GetSize(); i++)
|
|
|
|
{
|
|
|
|
if (Objects[i]->GetType() == LC_OBJECT_PIECE)
|
|
|
|
{
|
|
|
|
Group* pGroup = ((Piece*)Objects[i])->GetTopGroup();
|
|
|
|
if (pGroup != NULL)
|
|
|
|
{
|
|
|
|
for (Piece* pPiece = m_pPieces; pPiece; pPiece = pPiece->m_pNext)
|
|
|
|
if ((pPiece->IsVisible(m_bAnimation ? m_nCurFrame : m_nCurStep, m_bAnimation)) &&
|
|
|
|
(pPiece->GetTopGroup() == pGroup))
|
|
|
|
pPiece->Select (true, false, false);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
Objects[i]->Select(true, false, Control);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
Objects[i]->Select(true, false, Control);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Update screen and UI.
|
|
|
|
UpdateSelection();
|
|
|
|
UpdateAllViews();
|
|
|
|
SystemUpdateFocus(NULL);
|
|
|
|
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case LC_ACTION_MOVE:
|
|
|
|
{
|
|
|
|
SetModifiedFlag(true);
|
|
|
|
CheckPoint("Moving");
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case LC_ACTION_ROTATE:
|
|
|
|
{
|
|
|
|
SetModifiedFlag(true);
|
|
|
|
CheckPoint("Rotating");
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case LC_ACTION_CAMERA:
|
|
|
|
{
|
|
|
|
SystemUpdateCameraMenu(m_pCameras);
|
|
|
|
SystemUpdateCurrentCamera(NULL, m_pViewCameras[m_nActiveViewport], m_pCameras);
|
|
|
|
SetModifiedFlag(true);
|
|
|
|
CheckPoint("Inserting");
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case LC_ACTION_CURVE:
|
|
|
|
{
|
|
|
|
SetModifiedFlag(true);
|
|
|
|
CheckPoint("Inserting");
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case LC_ACTION_SPOTLIGHT:
|
|
|
|
{
|
|
|
|
SetModifiedFlag(true);
|
|
|
|
CheckPoint("Inserting");
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case LC_ACTION_ZOOM:
|
|
|
|
case LC_ACTION_PAN:
|
|
|
|
case LC_ACTION_ROTATE_VIEW:
|
|
|
|
case LC_ACTION_ROLL:
|
|
|
|
{
|
|
|
|
// For some reason the scene doesn't get redrawn when changing a camera but it does
|
|
|
|
// when moving things around, so manually get the full scene rendered again.
|
|
|
|
if (m_nDetail & LC_DET_FAST)
|
|
|
|
UpdateAllViews();
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case LC_ACTION_ZOOM_REGION:
|
|
|
|
{
|
|
|
|
int Viewport[4] =
|
|
|
|
{
|
|
|
|
(int)(viewports[m_nViewportMode].dim[m_nActiveViewport][0] * (float)m_nViewX),
|
|
|
|
(int)(viewports[m_nViewportMode].dim[m_nActiveViewport][1] * (float)m_nViewY),
|
|
|
|
(int)(viewports[m_nViewportMode].dim[m_nActiveViewport][2] * (float)m_nViewX),
|
|
|
|
(int)(viewports[m_nViewportMode].dim[m_nActiveViewport][3] * (float)m_nViewY)
|
|
|
|
};
|
|
|
|
|
|
|
|
float Aspect = (float)Viewport[2]/(float)Viewport[3];
|
|
|
|
Camera* Cam = m_pViewCameras[m_nActiveViewport];
|
|
|
|
|
|
|
|
// Build the matrices.
|
|
|
|
Matrix44 ModelView, Projection;
|
|
|
|
ModelView.CreateLookAt(Cam->GetEyePosition(), Cam->GetTargetPosition(), Cam->GetUpVector());
|
|
|
|
Projection.CreatePerspective(Cam->m_fovy, Aspect, Cam->m_zNear, Cam->m_zFar);
|
|
|
|
|
|
|
|
// Find out the top-left and bottom-right corners in screen coordinates.
|
|
|
|
float Left, Top, Bottom, Right;
|
|
|
|
|
|
|
|
if (m_OverlayTrackStart[0] < m_nDownX)
|
|
|
|
{
|
|
|
|
Left = m_OverlayTrackStart[0];
|
|
|
|
Right = (float)m_nDownX;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
Left = (float)m_nDownX;
|
|
|
|
Right = m_OverlayTrackStart[0];
|
|
|
|
}
|
|
|
|
|
|
|
|
if (m_OverlayTrackStart[1] > m_nDownY)
|
|
|
|
{
|
|
|
|
Top = m_OverlayTrackStart[1];
|
|
|
|
Bottom = (float)m_nDownY;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
Top = (float)m_nDownY;
|
|
|
|
Bottom = m_OverlayTrackStart[1];
|
|
|
|
}
|
|
|
|
|
|
|
|
// Unproject screen points to world space.
|
|
|
|
Vector3 Points[3] =
|
|
|
|
{
|
|
|
|
Vector3((Left + Right) / 2, (Top + Bottom) / 2, 0.9f),
|
|
|
|
Vector3((float)Viewport[2] / 2.0f, (float)Viewport[3] / 2.0f, 0.9f),
|
|
|
|
Vector3((float)Viewport[2] / 2.0f, (float)Viewport[3] / 2.0f, 0.1f),
|
|
|
|
};
|
|
|
|
|
|
|
|
UnprojectPoints(Points, 3, ModelView, Projection, Viewport);
|
|
|
|
|
|
|
|
// Center camera.
|
|
|
|
Vector3 Eye = Cam->GetEyePosition();
|
|
|
|
Eye = Eye + (Points[0] - Points[1]);
|
|
|
|
|
|
|
|
Vector3 Target = Cam->GetTargetPosition();
|
|
|
|
Target = Target + (Points[0] - Points[1]);
|
|
|
|
|
|
|
|
// Zoom in/out.
|
|
|
|
float RatioX = (Right - Left) / Viewport[2];
|
|
|
|
float RatioY = (Top - Bottom) / Viewport[3];
|
|
|
|
float ZoomFactor = -max(RatioX, RatioY) + 0.75f;
|
|
|
|
|
|
|
|
Vector3 Dir = Points[1] - Points[2];
|
|
|
|
Eye = Eye + Dir * ZoomFactor;
|
|
|
|
Target = Target + Dir * ZoomFactor;
|
|
|
|
|
|
|
|
// Change the camera and redraw.
|
|
|
|
Cam->ChangeKey(m_bAnimation ? m_nCurFrame : m_nCurStep, m_bAnimation, m_bAddKeys, Eye, LC_CK_EYE);
|
|
|
|
Cam->ChangeKey(m_bAnimation ? m_nCurFrame : m_nCurStep, m_bAnimation, m_bAddKeys, Target, LC_CK_TARGET);
|
|
|
|
Cam->UpdatePosition(m_bAnimation ? m_nCurFrame : m_nCurStep, m_bAnimation);
|
|
|
|
|
|
|
|
SystemUpdateFocus(NULL);
|
|
|
|
UpdateAllViews();
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case LC_ACTION_INSERT:
|
|
|
|
case LC_ACTION_LIGHT:
|
|
|
|
case LC_ACTION_ERASER:
|
|
|
|
case LC_ACTION_PAINT:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (m_pTrackFile != NULL)
|
|
|
|
{
|
|
|
|
if ((m_nCurAction == LC_ACTION_SELECT) || (m_nCurAction == LC_ACTION_ZOOM_REGION))
|
|
|
|
{
|
|
|
|
UpdateAllViews();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
DeleteContents (true);
|
|
|
|
FileLoad (m_pTrackFile, true, false);
|
|
|
|
delete m_pTrackFile;
|
|
|
|
m_pTrackFile = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Project::StartTracking(int mode)
|
|
|
|
{
|
|
|
|
SystemCaptureMouse();
|
|
|
|
m_nTracking = mode;
|
|
|
|
|
|
|
|
if (m_pTrackFile != NULL)
|
|
|
|
m_pTrackFile->SetLength (0);
|
|
|
|
else
|
|
|
|
m_pTrackFile = new FileMem;
|
|
|
|
|
|
|
|
FileSave(m_pTrackFile, true);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Project::GetSnapIndex(int* SnapXY, int* SnapZ) const
|
|
|
|
{
|
|
|
|
*SnapXY = (m_nMoveSnap & 0xff);
|
|
|
|
*SnapZ = ((m_nMoveSnap >> 8) & 0xff);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Project::GetSnapDistance(float* SnapXY, float* SnapZ) const
|
|
|
|
{
|
|
|
|
const float SnapXYTable[] = { 0.01f, 0.04f, 0.2f, 0.32f, 0.4f, 0.8f, 1.6f, 2.4f, 3.2f, 6.4f };
|
|
|
|
const float SnapZTable[] = { 0.01f, 0.04f, 0.2f, 0.32f, 0.4f, 0.8f, 0.96f, 1.92f, 3.84f, 7.68f };
|
|
|
|
|
|
|
|
int SXY, SZ;
|
|
|
|
GetSnapIndex(&SXY, &SZ);
|
|
|
|
|
|
|
|
SXY = min(SXY, 9);
|
|
|
|
SZ = min(SZ, 9);
|
|
|
|
|
|
|
|
*SnapXY = SnapXYTable[SXY];
|
|
|
|
*SnapZ = SnapZTable[SZ];
|
|
|
|
}
|
|
|
|
|
|
|
|
void Project::GetSnapDistanceText(char* SnapXY, char* SnapZ) const
|
|
|
|
{
|
|
|
|
if (m_nSnap & LC_DRAW_CM_UNITS)
|
|
|
|
{
|
|
|
|
float xy, z;
|
|
|
|
|
|
|
|
GetSnapDistance(&xy, &z);
|
|
|
|
|
|
|
|
sprintf(SnapXY, "%.2f", xy);
|
|
|
|
sprintf(SnapZ, "%.2f", z);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
const char* SnapXYText[] = { "0", "1/20S", "1/4S", "1F", "1/2S", "1S", "2S", "3S", "4S", "8S" };
|
|
|
|
const char* SnapZText[] = { "0", "1/20S", "1/4S", "1F", "1/2S", "1S", "1B", "2B", "4B", "8B" };
|
|
|
|
|
|
|
|
int SXY, SZ;
|
|
|
|
GetSnapIndex(&SXY, &SZ);
|
|
|
|
|
|
|
|
SXY = min(SXY, 9);
|
|
|
|
SZ = min(SZ, 9);
|
|
|
|
|
|
|
|
strcpy(SnapXY, SnapXYText[SXY]);
|
|
|
|
strcpy(SnapZ, SnapZText[SZ]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Project::SnapVector(Vector3& Delta, Vector3& Leftover) const
|
|
|
|
{
|
|
|
|
float SnapXY, SnapZ;
|
|
|
|
GetSnapDistance(&SnapXY, &SnapZ);
|
|
|
|
|
|
|
|
if (m_nSnap & LC_DRAW_SNAP_X)
|
|
|
|
{
|
|
|
|
int i = (int)(Delta[0] / SnapXY);
|
|
|
|
Leftover[0] = Delta[0] - (SnapXY * i);
|
|
|
|
|
|
|
|
if (Leftover[0] > SnapXY / 2)
|
|
|
|
{
|
|
|
|
Leftover[0] -= SnapXY;
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
else if (Leftover[0] < -SnapXY / 2)
|
|
|
|
{
|
|
|
|
Leftover[0] += SnapXY;
|
|
|
|
i--;
|
|
|
|
}
|
|
|
|
|
|
|
|
Delta[0] = SnapXY * i;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (m_nSnap & LC_DRAW_SNAP_Y)
|
|
|
|
{
|
|
|
|
int i = (int)(Delta[1] / SnapXY);
|
|
|
|
Leftover[1] = Delta[1] - (SnapXY * i);
|
|
|
|
|
|
|
|
if (Leftover[1] > SnapXY / 2)
|
|
|
|
{
|
|
|
|
Leftover[1] -= SnapXY;
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
else if (Leftover[1] < -SnapXY / 2)
|
|
|
|
{
|
|
|
|
Leftover[1] += SnapXY;
|
|
|
|
i--;
|
|
|
|
}
|
|
|
|
|
|
|
|
Delta[1] = SnapXY * i;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (m_nSnap & LC_DRAW_SNAP_Z)
|
|
|
|
{
|
|
|
|
int i = (int)(Delta[2] / SnapZ);
|
|
|
|
Leftover[2] = Delta[2] - (SnapZ * i);
|
|
|
|
|
|
|
|
if (Leftover[2] > SnapZ / 2)
|
|
|
|
{
|
|
|
|
Leftover[2] -= SnapZ;
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
else if (Leftover[2] < -SnapZ / 2)
|
|
|
|
{
|
|
|
|
Leftover[2] += SnapZ;
|
|
|
|
i--;
|
|
|
|
}
|
|
|
|
|
|
|
|
Delta[2] = SnapZ * i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Project::SnapRotationVector(Vector3& Delta, Vector3& Leftover) const
|
|
|
|
{
|
|
|
|
if (m_nSnap & LC_DRAW_SNAP_A)
|
|
|
|
{
|
|
|
|
int Snap[3];
|
|
|
|
|
|
|
|
for (int i = 0; i < 3; i++)
|
|
|
|
{
|
|
|
|
Snap[i] = (int)(Delta[i] / (float)m_nAngleSnap);
|
|
|
|
}
|
|
|
|
|
|
|
|
Vector3 NewDelta((float)(m_nAngleSnap * Snap[0]), (float)(m_nAngleSnap * Snap[1]), (float)(m_nAngleSnap * Snap[2]));
|
|
|
|
Leftover = Delta - NewDelta;
|
|
|
|
Delta = NewDelta;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Project::MoveSelectedObjects(Vector3& Move, Vector3& Remainder, bool Snap)
|
|
|
|
{
|
|
|
|
// Don't move along locked directions.
|
|
|
|
if (m_nSnap & LC_DRAW_LOCK_X)
|
|
|
|
Move[0] = 0;
|
|
|
|
|
|
|
|
if (m_nSnap & LC_DRAW_LOCK_Y)
|
|
|
|
Move[1] = 0;
|
|
|
|
|
|
|
|
if (m_nSnap & LC_DRAW_LOCK_Z)
|
|
|
|
Move[2] = 0;
|
|
|
|
|
|
|
|
// Snap.
|
|
|
|
if (Snap)
|
|
|
|
{
|
|
|
|
SnapVector(Move, Remainder);
|
|
|
|
|
|
|
|
if (Move.LengthSquared() < 0.001f)
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Transform the translation if we're in relative mode.
|
|
|
|
if ((m_nSnap & LC_DRAW_GLOBAL_SNAP) == 0)
|
|
|
|
{
|
|
|
|
Object* Focus = GetFocusObject();
|
|
|
|
|
|
|
|
if ((Focus != NULL) && Focus->IsPiece())
|
|
|
|
{
|
|
|
|
float Rot[4];
|
|
|
|
((Piece*)Focus)->GetRotation(Rot);
|
|
|
|
|
|
|
|
Matrix33 RotMat;
|
|
|
|
RotMat.CreateFromAxisAngle(Vector3(Rot[0], Rot[1], Rot[2]), Rot[3] * LC_DTOR);
|
|
|
|
|
|
|
|
Move = Mul(Move, RotMat);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Piece* pPiece;
|
|
|
|
Camera* pCamera;
|
|
|
|
Light* pLight;
|
|
|
|
float x = Move[0], y = Move[1], z = Move[2];
|
|
|
|
|
|
|
|
for (pCamera = m_pCameras; pCamera; pCamera = pCamera->m_pNext)
|
|
|
|
if (pCamera->IsSelected())
|
|
|
|
{
|
|
|
|
pCamera->Move(m_bAnimation ? m_nCurFrame : m_nCurStep, m_bAnimation, m_bAddKeys, x, y, z);
|
|
|
|
pCamera->UpdatePosition(m_bAnimation ? m_nCurFrame : m_nCurStep, m_bAnimation);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (pLight = m_pLights; pLight; pLight = pLight->m_pNext)
|
|
|
|
if (pLight->IsSelected())
|
|
|
|
{
|
|
|
|
pLight->Move (m_bAnimation ? m_nCurFrame : m_nCurStep, m_bAnimation, m_bAddKeys, x, y, z);
|
|
|
|
pLight->UpdatePosition (m_bAnimation ? m_nCurFrame : m_nCurStep, m_bAnimation);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (pPiece = m_pPieces; pPiece; pPiece = pPiece->m_pNext)
|
|
|
|
if (pPiece->IsSelected())
|
|
|
|
{
|
|
|
|
pPiece->Move(m_bAnimation ? m_nCurFrame : m_nCurStep, m_bAnimation, m_bAddKeys, x, y, z);
|
|
|
|
pPiece->UpdatePosition(m_bAnimation ? m_nCurFrame : m_nCurStep, m_bAnimation);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (pPiece = m_pPieces; pPiece; pPiece = pPiece->m_pNext)
|
|
|
|
if (pPiece->IsSelected())
|
|
|
|
pPiece->CalculateConnections(m_pConnections, m_bAnimation ? m_nCurFrame : m_nCurStep, m_bAnimation, false, true);
|
|
|
|
|
|
|
|
// TODO: move group centers
|
|
|
|
|
|
|
|
if (m_OverlayActive)
|
|
|
|
{
|
|
|
|
if (!GetFocusPosition(m_OverlayCenter))
|
|
|
|
GetSelectionCenter(m_OverlayCenter);
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Project::RotateSelectedObjects(Vector3& Delta, Vector3& Remainder)
|
|
|
|
{
|
|
|
|
// Don't move along locked directions.
|
|
|
|
if (m_nSnap & LC_DRAW_LOCK_X)
|
|
|
|
Delta[0] = 0;
|
|
|
|
|
|
|
|
if (m_nSnap & LC_DRAW_LOCK_Y)
|
|
|
|
Delta[1] = 0;
|
|
|
|
|
|
|
|
if (m_nSnap & LC_DRAW_LOCK_Z)
|
|
|
|
Delta[2] = 0;
|
|
|
|
|
|
|
|
// Snap.
|
|
|
|
SnapRotationVector(Delta, Remainder);
|
|
|
|
|
|
|
|
if (Delta.LengthSquared() < 0.001f)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
float bs[6] = { 10000, 10000, 10000, -10000, -10000, -10000 };
|
|
|
|
float pos[3], rot[4];
|
|
|
|
int nSel = 0;
|
|
|
|
Piece *pPiece, *pFocus = NULL;
|
|
|
|
|
|
|
|
for (pPiece = m_pPieces; pPiece; pPiece = pPiece->m_pNext)
|
|
|
|
{
|
|
|
|
if (pPiece->IsSelected())
|
|
|
|
{
|
|
|
|
if (pPiece->IsFocused())
|
|
|
|
pFocus = pPiece;
|
|
|
|
|
|
|
|
pPiece->CompareBoundingBox(bs);
|
|
|
|
nSel++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (pFocus != NULL)
|
|
|
|
{
|
|
|
|
pFocus->GetPosition(pos);
|
|
|
|
bs[0] = bs[3] = pos[0];
|
|
|
|
bs[1] = bs[4] = pos[1];
|
|
|
|
bs[2] = bs[5] = pos[2];
|
|
|
|
}
|
|
|
|
|
|
|
|
Vector3 Center((bs[0]+bs[3])/2, (bs[1]+bs[4])/2, (bs[2]+bs[5])/2);
|
|
|
|
|
|
|
|
// Create the rotation matrix.
|
|
|
|
Quaternion Rotation(0, 0, 0, 1);
|
|
|
|
Quaternion WorldToFocus, FocusToWorld;
|
|
|
|
|
|
|
|
if (!(m_nSnap & LC_DRAW_LOCK_X) && (Delta[0] != 0.0f))
|
|
|
|
{
|
|
|
|
Quaternion q;
|
|
|
|
q.CreateRotationX(Delta[0] * LC_DTOR);
|
|
|
|
Rotation = Mul(q, Rotation);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!(m_nSnap & LC_DRAW_LOCK_Y) && (Delta[1] != 0.0f))
|
|
|
|
{
|
|
|
|
Quaternion q;
|
|
|
|
q.CreateRotationY(Delta[1] * LC_DTOR);
|
|
|
|
Rotation = Mul(q, Rotation);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!(m_nSnap & LC_DRAW_LOCK_Z) && (Delta[2] != 0.0f))
|
|
|
|
{
|
|
|
|
Quaternion q;
|
|
|
|
q.CreateRotationZ(Delta[2] * LC_DTOR);
|
|
|
|
Rotation = Mul(q, Rotation);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Transform the rotation relative to the focused piece.
|
|
|
|
if (m_nSnap & LC_DRAW_GLOBAL_SNAP)
|
|
|
|
pFocus = NULL;
|
|
|
|
|
|
|
|
if (pFocus != NULL)
|
|
|
|
{
|
|
|
|
float Rot[4];
|
|
|
|
((Piece*)pFocus)->GetRotation(Rot);
|
|
|
|
|
|
|
|
WorldToFocus.FromAxisAngle(Vector4(Rot[0], Rot[1], Rot[2], -Rot[3] * LC_DTOR));
|
|
|
|
FocusToWorld.FromAxisAngle(Vector4(Rot[0], Rot[1], Rot[2], Rot[3] * LC_DTOR));
|
|
|
|
|
|
|
|
Rotation = Mul(FocusToWorld, Rotation);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (pPiece = m_pPieces; pPiece; pPiece = pPiece->m_pNext)
|
|
|
|
{
|
|
|
|
if (!pPiece->IsSelected())
|
|
|
|
continue;
|
|
|
|
|
|
|
|
pPiece->GetPosition(pos);
|
|
|
|
pPiece->GetRotation(rot);
|
|
|
|
|
|
|
|
Vector4 NewRotation;
|
|
|
|
|
|
|
|
if ((nSel == 1) && (pFocus == pPiece))
|
|
|
|
{
|
|
|
|
Quaternion LocalToWorld;
|
|
|
|
LocalToWorld.FromAxisAngle(Vector4(rot[0], rot[1], rot[2], rot[3] * LC_DTOR));
|
|
|
|
|
|
|
|
Quaternion NewLocalToWorld;
|
|
|
|
|
|
|
|
if (pFocus != NULL)
|
|
|
|
{
|
|
|
|
Quaternion LocalToFocus = Mul(WorldToFocus, LocalToWorld);
|
|
|
|
NewLocalToWorld = Mul(LocalToFocus, Rotation);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
NewLocalToWorld = Mul(Rotation, LocalToWorld);
|
|
|
|
}
|
|
|
|
|
|
|
|
NewLocalToWorld.ToAxisAngle(NewRotation);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
Vector3 Distance = Vector3(pos[0], pos[1], pos[2]) - Center;
|
|
|
|
|
|
|
|
Quaternion LocalToWorld;
|
|
|
|
LocalToWorld.FromAxisAngle(Vector4(rot[0], rot[1], rot[2], rot[3] * LC_DTOR));
|
|
|
|
|
|
|
|
Quaternion NewLocalToWorld;
|
|
|
|
|
|
|
|
if (pFocus != NULL)
|
|
|
|
{
|
|
|
|
Quaternion LocalToFocus = Mul(WorldToFocus, LocalToWorld);
|
|
|
|
NewLocalToWorld = Mul(Rotation, LocalToFocus);
|
|
|
|
|
|
|
|
Quaternion WorldToLocal;
|
|
|
|
WorldToLocal.FromAxisAngle(Vector4(rot[0], rot[1], rot[2], -rot[3] * LC_DTOR));
|
|
|
|
|
|
|
|
Distance = Mul(Distance, WorldToLocal);
|
|
|
|
Distance = Mul(Distance, NewLocalToWorld);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
NewLocalToWorld = Mul(Rotation, LocalToWorld);
|
|
|
|
|
|
|
|
Distance = Mul(Distance, Rotation);
|
|
|
|
}
|
|
|
|
|
|
|
|
NewLocalToWorld.ToAxisAngle(NewRotation);
|
|
|
|
|
|
|
|
pos[0] = Center[0] + Distance[0];
|
|
|
|
pos[1] = Center[1] + Distance[1];
|
|
|
|
pos[2] = Center[2] + Distance[2];
|
|
|
|
|
|
|
|
pPiece->ChangeKey(m_bAnimation ? m_nCurFrame : m_nCurStep, m_bAnimation, m_bAddKeys, pos, LC_PK_POSITION);
|
|
|
|
}
|
|
|
|
|
|
|
|
rot[0] = NewRotation[0];
|
|
|
|
rot[1] = NewRotation[1];
|
|
|
|
rot[2] = NewRotation[2];
|
|
|
|
rot[3] = NewRotation[3] * LC_RTOD;
|
|
|
|
|
|
|
|
pPiece->ChangeKey(m_bAnimation ? m_nCurFrame : m_nCurStep, m_bAnimation, m_bAddKeys, rot, LC_PK_ROTATION);
|
|
|
|
pPiece->UpdatePosition(m_bAnimation ? m_nCurFrame : m_nCurStep, m_bAnimation);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (pPiece = m_pPieces; pPiece; pPiece = pPiece->m_pNext)
|
|
|
|
if (pPiece->IsSelected())
|
|
|
|
pPiece->CalculateConnections(m_pConnections, m_bAnimation ? m_nCurFrame : m_nCurStep, m_bAnimation, false, true);
|
|
|
|
|
|
|
|
if (m_OverlayActive)
|
|
|
|
{
|
|
|
|
if (!GetFocusPosition(m_OverlayCenter))
|
|
|
|
GetSelectionCenter(m_OverlayCenter);
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Project::OnKeyDown(char nKey, bool bControl, bool bShift)
|
|
|
|
{
|
|
|
|
bool ret = false;
|
|
|
|
|
|
|
|
if (IsDrawing())
|
|
|
|
return false;
|
|
|
|
|
|
|
|
// FIXME: Almost all of this should go through the keyboard shortcut system.
|
|
|
|
switch (nKey)
|
|
|
|
{
|
|
|
|
case KEY_ESCAPE:
|
|
|
|
{
|
|
|
|
if (m_nTracking != LC_TRACK_NONE)
|
|
|
|
StopTracking(false);
|
|
|
|
ret = true;
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case KEY_INSERT:
|
|
|
|
{
|
|
|
|
HandleCommand(LC_PIECE_INSERT, 0);
|
|
|
|
ret = true;
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case KEY_DELETE:
|
|
|
|
{
|
|
|
|
HandleCommand(LC_PIECE_DELETE, 0);
|
|
|
|
ret = true;
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case '0': case '1': case '2': case '3': case '4':
|
|
|
|
case '5': case '6': case '7': case '8': case '9':
|
|
|
|
{
|
|
|
|
if (bControl)
|
|
|
|
{
|
|
|
|
m_nCurClipboard = nKey - 0x30;
|
|
|
|
SystemUpdatePaste(m_pClipboard[m_nCurClipboard] != NULL);
|
|
|
|
ret = true;
|
|
|
|
}
|
|
|
|
} break;
|
|
|
|
|
|
|
|
|
|
|
|
case KEY_PLUS: // case '+': case '=':
|
|
|
|
{
|
|
|
|
if (bShift)
|
|
|
|
HandleCommand(LC_VIEW_ZOOM, -10);
|
|
|
|
else
|
|
|
|
HandleCommand(LC_VIEW_ZOOM, -1);
|
|
|
|
|
|
|
|
ret = true;
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case KEY_MINUS: // case '-': case '_':
|
|
|
|
{
|
|
|
|
if (bShift)
|
|
|
|
HandleCommand(LC_VIEW_ZOOM, 10);
|
|
|
|
else
|
|
|
|
HandleCommand(LC_VIEW_ZOOM, 1);
|
|
|
|
|
|
|
|
ret = true;
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case KEY_TAB:
|
|
|
|
{
|
|
|
|
if (m_pPieces == NULL)
|
|
|
|
break;
|
|
|
|
|
|
|
|
Piece* pFocus = NULL, *pPiece;
|
|
|
|
for (pFocus = m_pPieces; pFocus; pFocus = pFocus->m_pNext)
|
|
|
|
if (pFocus->IsFocused())
|
|
|
|
break;
|
|
|
|
|
|
|
|
SelectAndFocusNone(false);
|
|
|
|
|
|
|
|
if (pFocus == NULL)
|
|
|
|
{
|
|
|
|
if (bShift)
|
|
|
|
{
|
|
|
|
// Focus the last visible piece.
|
|
|
|
for (pPiece = m_pPieces; pPiece; pPiece = pPiece->m_pNext)
|
|
|
|
if (pPiece->IsVisible(m_bAnimation ? m_nCurFrame : m_nCurStep, m_bAnimation))
|
|
|
|
pFocus = pPiece;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// Focus the first visible piece.
|
|
|
|
for (pPiece = m_pPieces; pPiece; pPiece = pPiece->m_pNext)
|
|
|
|
if (pPiece->IsVisible(m_bAnimation ? m_nCurFrame : m_nCurStep, m_bAnimation))
|
|
|
|
{
|
|
|
|
pFocus = pPiece;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (bShift)
|
|
|
|
{
|
|
|
|
// Focus the previous visible piece.
|
|
|
|
Piece* pBest = pPiece = pFocus;
|
|
|
|
for (;;)
|
|
|
|
{
|
|
|
|
if (pPiece->IsVisible(m_bAnimation ? m_nCurFrame : m_nCurStep, m_bAnimation))
|
|
|
|
pBest = pPiece;
|
|
|
|
|
|
|
|
if (pPiece->m_pNext != NULL)
|
|
|
|
{
|
|
|
|
if (pPiece->m_pNext == pFocus)
|
|
|
|
break;
|
|
|
|
else
|
|
|
|
pPiece = pPiece->m_pNext;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (pFocus == m_pPieces)
|
|
|
|
break;
|
|
|
|
else
|
|
|
|
pPiece = m_pPieces;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pFocus = pBest;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// Focus the next visible piece.
|
|
|
|
pPiece = pFocus;
|
|
|
|
for (;;)
|
|
|
|
{
|
|
|
|
if (pPiece != pFocus)
|
|
|
|
if (pPiece->IsVisible(m_bAnimation ? m_nCurFrame : m_nCurStep, m_bAnimation))
|
|
|
|
{
|
|
|
|
pFocus = pPiece;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (pPiece->m_pNext != NULL)
|
|
|
|
{
|
|
|
|
if (pPiece->m_pNext == pFocus)
|
|
|
|
break;
|
|
|
|
else
|
|
|
|
pPiece = pPiece->m_pNext;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (pFocus == m_pPieces)
|
|
|
|
break;
|
|
|
|
else
|
|
|
|
pPiece = m_pPieces;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (pFocus != NULL)
|
|
|
|
{
|
|
|
|
pFocus->Select (true, true, false);
|
|
|
|
Group* pGroup = pFocus->GetTopGroup();
|
|
|
|
if (pGroup != NULL)
|
|
|
|
{
|
|
|
|
for (pPiece = m_pPieces; pPiece; pPiece = pPiece->m_pNext)
|
|
|
|
if ((pPiece->IsVisible(m_bAnimation ? m_nCurFrame : m_nCurStep, m_bAnimation)) &&
|
|
|
|
(pPiece->GetTopGroup() == pGroup))
|
|
|
|
pPiece->Select (true, false, false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
UpdateSelection();
|
|
|
|
UpdateAllViews();
|
|
|
|
SystemUpdateFocus(pFocus);
|
|
|
|
ret = true;
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case KEY_UP: case KEY_DOWN: case KEY_LEFT:
|
|
|
|
case KEY_RIGHT: case KEY_NEXT: case KEY_PRIOR:
|
|
|
|
// if (AnyObjectSelected(FALSE))
|
|
|
|
{
|
|
|
|
Vector3 axis;
|
|
|
|
if (bShift)
|
|
|
|
{
|
|
|
|
if (m_nSnap & LC_DRAW_SNAP_A)
|
|
|
|
axis[0] = axis[1] = axis[2] = m_nAngleSnap;
|
|
|
|
else
|
|
|
|
axis[0] = axis[1] = axis[2] = 1;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
float xy, z;
|
|
|
|
GetSnapDistance(&xy, &z);
|
|
|
|
|
|
|
|
axis[0] = axis[1] = xy;
|
|
|
|
axis[2] = z;
|
|
|
|
|
|
|
|
if (((m_nSnap & LC_DRAW_SNAP_X) == 0) || bControl)
|
|
|
|
axis[0] = 0.01f;
|
|
|
|
if (((m_nSnap & LC_DRAW_SNAP_Y) == 0) || bControl)
|
|
|
|
axis[1] = 0.01f;
|
|
|
|
if (((m_nSnap & LC_DRAW_SNAP_Z) == 0) || bControl)
|
|
|
|
axis[2] = 0.01f;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (m_nSnap & LC_DRAW_MOVEAXIS)
|
|
|
|
{
|
|
|
|
switch (nKey)
|
|
|
|
{
|
|
|
|
case KEY_UP: {
|
|
|
|
axis[1] = axis[2] = 0; axis[0] = -axis[0];
|
|
|
|
} break;
|
|
|
|
case KEY_DOWN: {
|
|
|
|
axis[1] = axis[2] = 0;
|
|
|
|
} break;
|
|
|
|
case KEY_LEFT: {
|
|
|
|
axis[0] = axis[2] = 0; axis[1] = -axis[1];
|
|
|
|
} break;
|
|
|
|
case KEY_RIGHT: {
|
|
|
|
axis[0] = axis[2] = 0;
|
|
|
|
} break;
|
|
|
|
case KEY_NEXT: {
|
|
|
|
axis[0] = axis[1] = 0; axis[2] = -axis[2];
|
|
|
|
} break;
|
|
|
|
case KEY_PRIOR: {
|
|
|
|
axis[0] = axis[1] = 0;
|
|
|
|
} break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
Camera *camera = m_pViewCameras[m_nActiveViewport];
|
|
|
|
|
|
|
|
if (camera->IsSide ())
|
|
|
|
{
|
|
|
|
Matrix mat;
|
|
|
|
|
|
|
|
mat.CreateLookat (camera->GetEyePos (), camera->GetTargetPos (), camera->GetUpVec ());
|
|
|
|
mat.SetTranslation (0, 0, 0);
|
|
|
|
mat.Invert ();
|
|
|
|
|
|
|
|
switch (nKey)
|
|
|
|
{
|
|
|
|
case KEY_UP:
|
|
|
|
axis[0] = axis[2] = 0;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case KEY_DOWN:
|
|
|
|
axis[0] = axis[2] = 0; axis[1] = -axis[1];
|
|
|
|
break;
|
|
|
|
|
|
|
|
case KEY_LEFT:
|
|
|
|
axis[0] = -axis[0]; axis[1] = axis[2] = 0;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case KEY_RIGHT:
|
|
|
|
axis[1] = axis[2] = 0;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case KEY_NEXT:
|
|
|
|
axis[0] = axis[1] = 0; axis[2] = -axis[2];
|
|
|
|
break;
|
|
|
|
|
|
|
|
case KEY_PRIOR:
|
|
|
|
axis[0] = axis[1] = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
mat.TransformPoints (axis, 1);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
|
|
|
|
// TODO: rewrite this
|
|
|
|
|
|
|
|
switch (nKey)
|
|
|
|
{
|
|
|
|
case KEY_UP: {
|
|
|
|
axis[1] = axis[2] = 0; axis[0] = -axis[0];
|
|
|
|
} break;
|
|
|
|
case KEY_DOWN: {
|
|
|
|
axis[1] = axis[2] = 0;
|
|
|
|
} break;
|
|
|
|
case KEY_LEFT: {
|
|
|
|
axis[0] = axis[2] = 0; axis[1] = -axis[1];
|
|
|
|
} break;
|
|
|
|
case KEY_RIGHT: {
|
|
|
|
axis[0] = axis[2] = 0;
|
|
|
|
} break;
|
|
|
|
case KEY_NEXT: {
|
|
|
|
axis[0] = axis[1] = 0; axis[2] = -axis[2];
|
|
|
|
} break;
|
|
|
|
case KEY_PRIOR: {
|
|
|
|
axis[0] = axis[1] = 0;
|
|
|
|
} break;
|
|
|
|
}
|
|
|
|
|
|
|
|
GLdouble modelMatrix[16], projMatrix[16], p1[3], p2[3], p3[3];
|
|
|
|
float ax, ay;
|
|
|
|
GLint viewport[4];
|
|
|
|
|
|
|
|
glGetDoublev(GL_MODELVIEW_MATRIX, modelMatrix);
|
|
|
|
glGetDoublev(GL_PROJECTION_MATRIX, projMatrix);
|
|
|
|
glGetIntegerv(GL_VIEWPORT, viewport);
|
|
|
|
gluUnProject( 5, 5, 0.1, modelMatrix,projMatrix,viewport,&p1[0],&p1[1],&p1[2]);
|
|
|
|
gluUnProject(10, 5, 0.1, modelMatrix,projMatrix,viewport,&p2[0],&p2[1],&p2[2]);
|
|
|
|
gluUnProject( 5,10, 0.1, modelMatrix,projMatrix,viewport,&p3[0],&p3[1],&p3[2]);
|
|
|
|
|
|
|
|
Vector vx((float)(p2[0] - p1[0]), (float)(p2[1] - p1[1]), 0);//p2[2] - p1[2] };
|
|
|
|
Vector x(1, 0, 0);
|
|
|
|
ax = vx.Angle(x);
|
|
|
|
|
|
|
|
Vector vy((float)(p3[0] - p1[0]), (float)(p3[1] - p1[1]), 0);//p2[2] - p1[2] };
|
|
|
|
Vector y(0, -1, 0);
|
|
|
|
ay = vy.Angle(y);
|
|
|
|
|
|
|
|
if (ax > 135)
|
|
|
|
axis[0] = -axis[0];
|
|
|
|
|
|
|
|
if (ay < 45)
|
|
|
|
axis[1] = -axis[1];
|
|
|
|
|
|
|
|
if (ax >= 45 && ax <= 135)
|
|
|
|
{
|
|
|
|
float tmp = axis[0];
|
|
|
|
|
|
|
|
ax = vx.Angle(y);
|
|
|
|
if (ax > 90)
|
|
|
|
{
|
|
|
|
axis[0] = -axis[1];
|
|
|
|
axis[1] = tmp;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
axis[0] = axis[1];
|
|
|
|
axis[1] = -tmp;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (bShift)
|
|
|
|
{
|
|
|
|
Vector3 tmp;
|
|
|
|
RotateSelectedObjects(axis, tmp);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
Vector3 tmp;
|
|
|
|
MoveSelectedObjects(axis, tmp, false);
|
|
|
|
}
|
|
|
|
|
|
|
|
UpdateOverlayScale();
|
|
|
|
UpdateAllViews();
|
|
|
|
SetModifiedFlag(true);
|
|
|
|
CheckPoint((bShift) ? "Rotating" : "Moving");
|
|
|
|
SystemUpdateFocus(NULL);
|
|
|
|
ret = true;
|
|
|
|
} break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Project::BeginPieceDrop(PieceInfo* Info)
|
|
|
|
{
|
|
|
|
StartTracking(LC_TRACK_LEFT);
|
|
|
|
|
|
|
|
m_PreviousAction = m_nCurAction;
|
|
|
|
m_PreviousPiece = m_pCurPiece;
|
|
|
|
|
|
|
|
m_pCurPiece = Info;
|
|
|
|
m_pCurPiece->AddRef();
|
|
|
|
SetAction(LC_ACTION_INSERT);
|
|
|
|
}
|
|
|
|
|
2011-09-20 01:03:28 +02:00
|
|
|
void Project::OnLeftButtonDown(View* view, int x, int y, bool bControl, bool bShift)
|
2011-09-07 23:06:51 +02:00
|
|
|
{
|
|
|
|
GLdouble modelMatrix[16], projMatrix[16], point[3];
|
|
|
|
GLint viewport[4];
|
|
|
|
|
|
|
|
if (IsDrawing())
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (m_nTracking != LC_TRACK_NONE)
|
|
|
|
if (StopTracking(false))
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (SetActiveViewport(x, y))
|
|
|
|
return;
|
|
|
|
|
|
|
|
m_bTrackCancel = false;
|
|
|
|
m_nDownX = x;
|
|
|
|
m_nDownY = y;
|
|
|
|
m_MouseTotalDelta = Vector3(0, 0, 0);
|
|
|
|
m_MouseSnapLeftover = Vector3(0, 0, 0);
|
|
|
|
|
|
|
|
LoadViewportProjection(m_nActiveViewport);
|
|
|
|
glGetDoublev(GL_MODELVIEW_MATRIX, modelMatrix);
|
|
|
|
glGetDoublev(GL_PROJECTION_MATRIX, projMatrix);
|
|
|
|
glGetIntegerv(GL_VIEWPORT, viewport);
|
|
|
|
|
|
|
|
gluUnProject(x, y, 0.9, modelMatrix, projMatrix, viewport, &point[0], &point[1], &point[2]);
|
|
|
|
m_fTrack[0] = (float)point[0]; m_fTrack[1] = (float)point[1]; m_fTrack[2] = (float)point[2];
|
|
|
|
|
|
|
|
switch (m_nCurAction)
|
|
|
|
{
|
|
|
|
case LC_ACTION_SELECT:
|
|
|
|
case LC_ACTION_ERASER:
|
|
|
|
case LC_ACTION_PAINT:
|
|
|
|
{
|
|
|
|
LC_CLICKLINE ClickLine;
|
|
|
|
FindObjectFromPoint (x, y, &ClickLine);
|
|
|
|
|
|
|
|
if (m_nCurAction == LC_ACTION_SELECT)
|
|
|
|
{
|
|
|
|
if (ClickLine.pClosest != NULL)
|
|
|
|
{
|
|
|
|
switch (ClickLine.pClosest->GetType ())
|
|
|
|
{
|
|
|
|
case LC_OBJECT_PIECE:
|
|
|
|
{
|
|
|
|
Piece* pPiece = (Piece*)ClickLine.pClosest;
|
|
|
|
Group* pGroup = pPiece->GetTopGroup();
|
|
|
|
bool bFocus = pPiece->IsFocused ();
|
|
|
|
|
|
|
|
SelectAndFocusNone (bControl);
|
|
|
|
|
|
|
|
// if a piece has focus deselect it, otherwise set the focus
|
|
|
|
pPiece->Select (!bFocus, !bFocus, false);
|
|
|
|
|
|
|
|
if (pGroup != NULL)
|
|
|
|
for (pPiece = m_pPieces; pPiece; pPiece = pPiece->m_pNext)
|
|
|
|
if (pPiece->GetTopGroup() == pGroup)
|
|
|
|
pPiece->Select (!bFocus, false, false);
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case LC_OBJECT_CAMERA:
|
|
|
|
case LC_OBJECT_CAMERA_TARGET:
|
|
|
|
case LC_OBJECT_LIGHT:
|
|
|
|
case LC_OBJECT_LIGHT_TARGET:
|
|
|
|
{
|
|
|
|
SelectAndFocusNone (bControl);
|
|
|
|
ClickLine.pClosest->Select (true, true, bControl);
|
|
|
|
} break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
SelectAndFocusNone (bControl);
|
|
|
|
|
|
|
|
UpdateSelection();
|
|
|
|
UpdateAllViews();
|
|
|
|
SystemUpdateFocus(ClickLine.pClosest);
|
|
|
|
|
|
|
|
StartTracking(LC_TRACK_START_LEFT);
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((m_nCurAction == LC_ACTION_ERASER) && (ClickLine.pClosest != NULL))
|
|
|
|
{
|
|
|
|
switch (ClickLine.pClosest->GetType ())
|
|
|
|
{
|
|
|
|
case LC_OBJECT_PIECE:
|
|
|
|
{
|
|
|
|
Piece* pPiece = (Piece*)ClickLine.pClosest;
|
|
|
|
RemovePiece(pPiece);
|
|
|
|
delete pPiece;
|
|
|
|
// CalculateStep();
|
|
|
|
RemoveEmptyGroups();
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case LC_OBJECT_CAMERA:
|
|
|
|
case LC_OBJECT_CAMERA_TARGET:
|
|
|
|
{
|
|
|
|
Camera* pCamera;
|
|
|
|
if (ClickLine.pClosest->GetType () == LC_OBJECT_CAMERA)
|
|
|
|
pCamera = (Camera*)ClickLine.pClosest;
|
|
|
|
else
|
|
|
|
pCamera = ((CameraTarget*)ClickLine.pClosest)->GetParent();
|
|
|
|
bool bCanDelete = pCamera->IsUser();
|
|
|
|
|
|
|
|
for (int i = 0; i < 4; i++)
|
|
|
|
if (pCamera == m_pViewCameras[i])
|
|
|
|
bCanDelete = false;
|
|
|
|
|
|
|
|
if (bCanDelete)
|
|
|
|
{
|
|
|
|
Camera* pPrev;
|
|
|
|
for (pPrev = m_pCameras; pPrev; pPrev = pPrev->m_pNext)
|
|
|
|
if (pPrev->m_pNext == pCamera)
|
|
|
|
{
|
|
|
|
pPrev->m_pNext = pCamera->m_pNext;
|
|
|
|
delete pCamera;
|
|
|
|
SystemUpdateCameraMenu(m_pCameras);
|
|
|
|
SystemUpdateCurrentCamera(NULL, m_pViewCameras[m_nActiveViewport], m_pCameras);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case LC_OBJECT_LIGHT:
|
|
|
|
case LC_OBJECT_LIGHT_TARGET:
|
|
|
|
{
|
|
|
|
// pos = m_Lights.Find(pObject->m_pParent);
|
|
|
|
// m_Lights.RemoveAt(pos);
|
|
|
|
// delete pObject->m_pParent;
|
|
|
|
} break;
|
|
|
|
}
|
|
|
|
|
|
|
|
UpdateSelection();
|
|
|
|
UpdateAllViews();
|
|
|
|
SetModifiedFlag(true);
|
|
|
|
CheckPoint("Deleting");
|
|
|
|
// AfxGetMainWnd()->PostMessage(WM_LC_UPDATE_INFO, NULL, OT_PIECE);
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((m_nCurAction == LC_ACTION_PAINT) && (ClickLine.pClosest != NULL) &&
|
|
|
|
(ClickLine.pClosest->GetType() == LC_OBJECT_PIECE))
|
|
|
|
{
|
|
|
|
Piece* pPiece = (Piece*)ClickLine.pClosest;
|
|
|
|
|
|
|
|
if (pPiece->GetColor() != m_nCurColor)
|
|
|
|
{
|
|
|
|
bool bTrans = pPiece->IsTransparent();
|
|
|
|
pPiece->SetColor(m_nCurColor);
|
|
|
|
if (bTrans != pPiece->IsTransparent())
|
|
|
|
pPiece->CalculateConnections(m_pConnections, m_bAnimation ? m_nCurFrame : m_nCurStep, m_bAnimation, true, true);
|
|
|
|
|
|
|
|
SetModifiedFlag(true);
|
|
|
|
CheckPoint("Painting");
|
|
|
|
SystemUpdateFocus(NULL);
|
|
|
|
UpdateAllViews();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case LC_ACTION_INSERT:
|
|
|
|
case LC_ACTION_LIGHT:
|
|
|
|
{
|
|
|
|
if (m_nCurAction == LC_ACTION_INSERT)
|
|
|
|
{
|
|
|
|
Vector3 Pos;
|
|
|
|
Vector4 Rot;
|
|
|
|
|
|
|
|
GetPieceInsertPosition(x, y, Pos, Rot);
|
|
|
|
|
|
|
|
Piece* pPiece = new Piece(m_pCurPiece);
|
|
|
|
pPiece->Initialize(Pos[0], Pos[1], Pos[2], m_nCurStep, m_nCurFrame, m_nCurColor);
|
|
|
|
|
|
|
|
pPiece->ChangeKey(m_nCurStep, false, false, Rot, LC_PK_ROTATION);
|
|
|
|
pPiece->ChangeKey(m_nCurFrame, true, false, Rot, LC_PK_ROTATION);
|
|
|
|
pPiece->UpdatePosition(m_bAnimation ? m_nCurFrame : m_nCurStep, m_bAnimation);
|
|
|
|
|
|
|
|
SelectAndFocusNone(false);
|
|
|
|
pPiece->CreateName(m_pPieces);
|
|
|
|
AddPiece(pPiece);
|
|
|
|
pPiece->CalculateConnections(m_pConnections, m_bAnimation ? m_nCurFrame : m_nCurStep, m_bAnimation, false, true);
|
|
|
|
pPiece->Select (true, true, false);
|
|
|
|
UpdateSelection();
|
|
|
|
SystemPieceComboAdd(m_pCurPiece->m_strDescription);
|
|
|
|
SystemUpdateFocus(pPiece);
|
|
|
|
|
|
|
|
if (m_nSnap & LC_DRAW_MOVE)
|
|
|
|
SetAction(LC_ACTION_MOVE);
|
|
|
|
}
|
|
|
|
else if (m_nCurAction == LC_ACTION_LIGHT)
|
|
|
|
{
|
|
|
|
GLint max;
|
|
|
|
int count = 0;
|
|
|
|
Light *pLight;
|
|
|
|
|
|
|
|
glGetIntegerv (GL_MAX_LIGHTS, &max);
|
|
|
|
for (pLight = m_pLights; pLight; pLight = pLight->m_pNext)
|
|
|
|
count++;
|
|
|
|
|
|
|
|
if (count == max)
|
|
|
|
break;
|
|
|
|
|
|
|
|
pLight = new Light (m_fTrack[0], m_fTrack[1], m_fTrack[2]);
|
|
|
|
|
|
|
|
SelectAndFocusNone (false);
|
|
|
|
|
|
|
|
pLight->CreateName(m_pLights);
|
|
|
|
pLight->m_pNext = m_pLights;
|
|
|
|
m_pLights = pLight;
|
|
|
|
SystemUpdateFocus (pLight);
|
|
|
|
pLight->Select (true, true, false);
|
|
|
|
UpdateSelection ();
|
|
|
|
}
|
|
|
|
|
|
|
|
// AfxGetMainWnd()->PostMessage(WM_LC_UPDATE_INFO, (WPARAM)pNew, OT_PIECE);
|
|
|
|
UpdateSelection();
|
|
|
|
UpdateAllViews();
|
|
|
|
SetModifiedFlag(true);
|
|
|
|
CheckPoint("Inserting");
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case LC_ACTION_SPOTLIGHT:
|
|
|
|
{
|
|
|
|
GLint max;
|
|
|
|
int count = 0;
|
|
|
|
Light *pLight;
|
|
|
|
|
|
|
|
glGetIntegerv (GL_MAX_LIGHTS, &max);
|
|
|
|
for (pLight = m_pLights; pLight; pLight = pLight->m_pNext)
|
|
|
|
count++;
|
|
|
|
|
|
|
|
if (count == max)
|
|
|
|
break;
|
|
|
|
|
|
|
|
double tmp[3];
|
|
|
|
gluUnProject(x+1, y-1, 0.9, modelMatrix, projMatrix, viewport, &tmp[0], &tmp[1], &tmp[2]);
|
|
|
|
SelectAndFocusNone(false);
|
|
|
|
StartTracking(LC_TRACK_START_LEFT);
|
|
|
|
pLight = new Light (m_fTrack[0], m_fTrack[1], m_fTrack[2], (float)tmp[0], (float)tmp[1], (float)tmp[2]);
|
|
|
|
pLight->GetTarget ()->Select (true, true, false);
|
|
|
|
pLight->m_pNext = m_pLights;
|
|
|
|
m_pLights = pLight;
|
|
|
|
UpdateSelection();
|
|
|
|
UpdateAllViews();
|
|
|
|
SystemUpdateFocus(pLight);
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case LC_ACTION_CAMERA:
|
|
|
|
{
|
|
|
|
double tmp[3];
|
|
|
|
gluUnProject(x+1, y-1, 0.9, modelMatrix, projMatrix, viewport, &tmp[0], &tmp[1], &tmp[2]);
|
|
|
|
SelectAndFocusNone(false);
|
|
|
|
StartTracking(LC_TRACK_START_LEFT);
|
|
|
|
Camera* pCamera = new Camera(m_fTrack[0], m_fTrack[1], m_fTrack[2], (float)tmp[0], (float)tmp[1], (float)tmp[2], m_pCameras);
|
|
|
|
pCamera->GetTarget ()->Select (true, true, false);
|
|
|
|
UpdateSelection();
|
|
|
|
UpdateAllViews();
|
|
|
|
SystemUpdateFocus(pCamera);
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case LC_ACTION_MOVE:
|
|
|
|
{
|
|
|
|
bool sel = false;
|
|
|
|
|
|
|
|
for (Piece* pPiece = m_pPieces; pPiece; pPiece = pPiece->m_pNext)
|
|
|
|
{
|
|
|
|
if (pPiece->IsSelected())
|
|
|
|
{
|
|
|
|
sel = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!sel)
|
|
|
|
{
|
|
|
|
for (Camera* pCamera = m_pCameras; pCamera; pCamera = pCamera->m_pNext)
|
|
|
|
{
|
|
|
|
if (pCamera->IsSelected())
|
|
|
|
{
|
|
|
|
sel = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!sel)
|
|
|
|
{
|
|
|
|
for (Light* pLight = m_pLights; pLight; pLight = pLight->m_pNext)
|
|
|
|
{
|
|
|
|
if (pLight->IsSelected())
|
|
|
|
{
|
|
|
|
sel = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (sel)
|
|
|
|
{
|
|
|
|
StartTracking(LC_TRACK_START_LEFT);
|
|
|
|
m_OverlayDelta = Vector3(0.0f, 0.0f, 0.0f);
|
|
|
|
m_MouseSnapLeftover = Vector3(0.0f, 0.0f, 0.0f);
|
|
|
|
}
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case LC_ACTION_ROTATE:
|
|
|
|
{
|
|
|
|
Piece* pPiece;
|
|
|
|
|
|
|
|
for (pPiece = m_pPieces; pPiece; pPiece = pPiece->m_pNext)
|
|
|
|
{
|
|
|
|
if (pPiece->IsSelected())
|
|
|
|
{
|
|
|
|
StartTracking(LC_TRACK_START_LEFT);
|
|
|
|
m_OverlayDelta = Vector3(0.0f, 0.0f, 0.0f);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case LC_ACTION_ZOOM_REGION:
|
|
|
|
{
|
|
|
|
m_OverlayTrackStart[0] = (float)x;
|
|
|
|
m_OverlayTrackStart[1] = (float)y;
|
|
|
|
StartTracking(LC_TRACK_START_LEFT);
|
|
|
|
ActivateOverlay();
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case LC_ACTION_ZOOM:
|
|
|
|
case LC_ACTION_ROLL:
|
|
|
|
case LC_ACTION_PAN:
|
|
|
|
case LC_ACTION_ROTATE_VIEW:
|
|
|
|
{
|
|
|
|
StartTracking(LC_TRACK_START_LEFT);
|
|
|
|
} break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-09-20 01:03:28 +02:00
|
|
|
void Project::OnLeftButtonDoubleClick(View* view, int x, int y, bool bControl, bool bShift)
|
2011-09-07 23:06:51 +02:00
|
|
|
{
|
|
|
|
GLdouble modelMatrix[16], projMatrix[16], point[3];
|
|
|
|
GLint viewport[4];
|
|
|
|
|
|
|
|
if (IsDrawing())
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (SetActiveViewport(x, y))
|
|
|
|
return;
|
|
|
|
|
|
|
|
LoadViewportProjection(m_nActiveViewport);
|
|
|
|
glGetDoublev (GL_MODELVIEW_MATRIX, modelMatrix);
|
|
|
|
glGetDoublev (GL_PROJECTION_MATRIX, projMatrix);
|
|
|
|
glGetIntegerv (GL_VIEWPORT, viewport);
|
|
|
|
|
|
|
|
// why this is here ?
|
|
|
|
gluUnProject(x, y, 0.9, modelMatrix, projMatrix, viewport, &point[0], &point[1], &point[2]);
|
|
|
|
m_fTrack[0] = (float)point[0]; m_fTrack[1] = (float)point[1]; m_fTrack[2] = (float)point[2];
|
|
|
|
|
|
|
|
LC_CLICKLINE ClickLine;
|
|
|
|
FindObjectFromPoint (x, y, &ClickLine);
|
|
|
|
|
|
|
|
// if (m_nCurAction == LC_ACTION_SELECT)
|
|
|
|
{
|
|
|
|
SelectAndFocusNone(bControl);
|
|
|
|
|
|
|
|
if (ClickLine.pClosest != NULL)
|
|
|
|
switch (ClickLine.pClosest->GetType ())
|
|
|
|
{
|
|
|
|
case LC_OBJECT_PIECE:
|
|
|
|
{
|
|
|
|
Piece* pPiece = (Piece*)ClickLine.pClosest;
|
|
|
|
pPiece->Select (true, true, false);
|
|
|
|
Group* pGroup = pPiece->GetTopGroup();
|
|
|
|
|
|
|
|
if (pGroup != NULL)
|
|
|
|
for (pPiece = m_pPieces; pPiece; pPiece = pPiece->m_pNext)
|
|
|
|
if (pPiece->GetTopGroup() == pGroup)
|
|
|
|
pPiece->Select (true, false, false);
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case LC_OBJECT_CAMERA:
|
|
|
|
case LC_OBJECT_CAMERA_TARGET:
|
|
|
|
case LC_OBJECT_LIGHT:
|
|
|
|
case LC_OBJECT_LIGHT_TARGET:
|
|
|
|
{
|
|
|
|
ClickLine.pClosest->Select (true, true, bControl);
|
|
|
|
} break;
|
|
|
|
}
|
|
|
|
|
|
|
|
UpdateSelection();
|
|
|
|
UpdateAllViews();
|
|
|
|
SystemUpdateFocus(ClickLine.pClosest);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-09-20 01:03:28 +02:00
|
|
|
void Project::OnLeftButtonUp(View* view, int x, int y, bool bControl, bool bShift)
|
2011-09-07 23:06:51 +02:00
|
|
|
{
|
|
|
|
if (m_nTracking == LC_TRACK_LEFT)
|
|
|
|
{
|
|
|
|
// Dragging a new piece from the tree.
|
|
|
|
if (m_nCurAction == LC_ACTION_INSERT)
|
|
|
|
{
|
|
|
|
int Viewport[4];
|
|
|
|
Viewport[0] = (int)(viewports[m_nViewportMode].dim[m_nActiveViewport][0] * (float)m_nViewX);
|
|
|
|
Viewport[1] = (int)(viewports[m_nViewportMode].dim[m_nActiveViewport][1] * (float)m_nViewY);
|
|
|
|
Viewport[2] = (int)(viewports[m_nViewportMode].dim[m_nActiveViewport][2] * (float)m_nViewX);
|
|
|
|
Viewport[3] = (int)(viewports[m_nViewportMode].dim[m_nActiveViewport][3] * (float)m_nViewY);
|
|
|
|
|
|
|
|
if ((x > Viewport[0]) && (x < Viewport[2]) && (y > Viewport[1]) && (y < Viewport[3]))
|
|
|
|
{
|
|
|
|
Vector3 Pos;
|
|
|
|
Vector4 Rot;
|
|
|
|
|
|
|
|
GetPieceInsertPosition(x, y, Pos, Rot);
|
|
|
|
|
|
|
|
Piece* pPiece = new Piece(m_pCurPiece);
|
|
|
|
pPiece->Initialize(Pos[0], Pos[1], Pos[2], m_nCurStep, m_nCurFrame, m_nCurColor);
|
|
|
|
|
|
|
|
pPiece->ChangeKey(m_nCurStep, false, false, Rot, LC_PK_ROTATION);
|
|
|
|
pPiece->ChangeKey(m_nCurFrame, true, false, Rot, LC_PK_ROTATION);
|
|
|
|
pPiece->UpdatePosition(m_bAnimation ? m_nCurFrame : m_nCurStep, m_bAnimation);
|
|
|
|
|
|
|
|
SelectAndFocusNone(false);
|
|
|
|
pPiece->CreateName(m_pPieces);
|
|
|
|
AddPiece(pPiece);
|
|
|
|
pPiece->CalculateConnections(m_pConnections, m_bAnimation ? m_nCurFrame : m_nCurStep, m_bAnimation, false, true);
|
|
|
|
pPiece->Select (true, true, false);
|
|
|
|
UpdateSelection();
|
|
|
|
SystemPieceComboAdd(m_pCurPiece->m_strDescription);
|
|
|
|
SystemUpdateFocus(pPiece);
|
|
|
|
|
|
|
|
if (m_nSnap & LC_DRAW_MOVE)
|
|
|
|
SetAction(LC_ACTION_MOVE);
|
|
|
|
else
|
|
|
|
SetAction(m_PreviousAction);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
SetAction(m_PreviousAction);
|
|
|
|
|
|
|
|
m_pCurPiece->DeRef();
|
|
|
|
m_pCurPiece = m_PreviousPiece;
|
|
|
|
m_PreviousPiece = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
StopTracking(true);
|
|
|
|
}
|
|
|
|
|
2011-09-20 01:03:28 +02:00
|
|
|
void Project::OnRightButtonDown(View* view, int x, int y, bool bControl, bool bShift)
|
2011-09-07 23:06:51 +02:00
|
|
|
{
|
|
|
|
GLdouble modelMatrix[16], projMatrix[16], point[3];
|
|
|
|
GLint viewport[4];
|
|
|
|
|
|
|
|
if (StopTracking(false))
|
|
|
|
return;
|
|
|
|
if (SetActiveViewport(x, y))
|
|
|
|
return;
|
|
|
|
|
|
|
|
m_nDownX = x;
|
|
|
|
m_nDownY = y;
|
|
|
|
m_bTrackCancel = false;
|
|
|
|
|
|
|
|
LoadViewportProjection(m_nActiveViewport);
|
|
|
|
glGetDoublev(GL_MODELVIEW_MATRIX, modelMatrix);
|
|
|
|
glGetDoublev(GL_PROJECTION_MATRIX, projMatrix);
|
|
|
|
glGetIntegerv(GL_VIEWPORT, viewport);
|
|
|
|
|
|
|
|
gluUnProject(x, y, 0.9, modelMatrix, projMatrix, viewport, &point[0], &point[1], &point[2]);
|
|
|
|
m_fTrack[0] = (float)point[0]; m_fTrack[1] = (float)point[1]; m_fTrack[2] = (float)point[2];
|
|
|
|
|
|
|
|
switch (m_nCurAction)
|
|
|
|
{
|
|
|
|
case LC_ACTION_MOVE:
|
|
|
|
{
|
|
|
|
bool sel = false;
|
|
|
|
|
|
|
|
for (Piece* pPiece = m_pPieces; pPiece; pPiece = pPiece->m_pNext)
|
|
|
|
if (pPiece->IsSelected())
|
|
|
|
{
|
|
|
|
sel = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!sel)
|
|
|
|
for (Camera* pCamera = m_pCameras; pCamera; pCamera = pCamera->m_pNext)
|
|
|
|
if (pCamera->IsSelected())
|
|
|
|
{
|
|
|
|
sel = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!sel)
|
|
|
|
for (Light* pLight = m_pLights; pLight; pLight = pLight->m_pNext)
|
|
|
|
if (pLight->IsSelected())
|
|
|
|
{
|
|
|
|
sel = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (sel)
|
|
|
|
{
|
|
|
|
StartTracking(LC_TRACK_START_RIGHT);
|
|
|
|
m_fTrack[0] = m_fTrack[1] = m_fTrack[2] = 0.0f;
|
|
|
|
}
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case LC_ACTION_ROTATE:
|
|
|
|
{
|
|
|
|
Piece* pPiece;
|
|
|
|
|
|
|
|
for (pPiece = m_pPieces; pPiece; pPiece = pPiece->m_pNext)
|
|
|
|
if (pPiece->IsSelected())
|
|
|
|
{
|
|
|
|
StartTracking(LC_TRACK_START_RIGHT);
|
|
|
|
m_fTrack[0] = m_fTrack[1] = m_fTrack[2] = 0.0f;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
} break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-09-20 01:03:28 +02:00
|
|
|
void Project::OnRightButtonUp(View* view, int x, int y, bool bControl, bool bShift)
|
2011-09-07 23:06:51 +02:00
|
|
|
{
|
|
|
|
if (!StopTracking(true) && !m_bTrackCancel)
|
|
|
|
SystemDoPopupMenu(1, -1, -1);
|
|
|
|
m_bTrackCancel = false;
|
|
|
|
}
|
|
|
|
|
2011-09-20 01:03:28 +02:00
|
|
|
void Project::OnMouseMove(View* view, int x, int y, bool bControl, bool bShift)
|
2011-09-07 23:06:51 +02:00
|
|
|
{
|
|
|
|
if ((m_nTracking == LC_TRACK_NONE) && (m_nCurAction != LC_ACTION_INSERT))
|
|
|
|
{
|
|
|
|
if (m_OverlayActive)
|
|
|
|
{
|
|
|
|
MouseUpdateOverlays(x, y);
|
|
|
|
}
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (m_nTracking == LC_TRACK_START_RIGHT)
|
|
|
|
m_nTracking = LC_TRACK_RIGHT;
|
|
|
|
|
|
|
|
if (m_nTracking == LC_TRACK_START_LEFT)
|
|
|
|
m_nTracking = LC_TRACK_LEFT;
|
|
|
|
|
|
|
|
if (IsDrawing())
|
|
|
|
return;
|
|
|
|
|
|
|
|
GLdouble modelMatrix[16], projMatrix[16], tmp[3];
|
|
|
|
GLint viewport[4];
|
|
|
|
float ptx, pty, ptz;
|
|
|
|
|
|
|
|
LoadViewportProjection(m_nActiveViewport);
|
|
|
|
glGetDoublev(GL_MODELVIEW_MATRIX, modelMatrix);
|
|
|
|
glGetDoublev(GL_PROJECTION_MATRIX, projMatrix);
|
|
|
|
glGetIntegerv(GL_VIEWPORT, viewport);
|
|
|
|
|
|
|
|
gluUnProject(x, y, 0.9, modelMatrix, projMatrix, viewport, &tmp[0], &tmp[1], &tmp[2]);
|
|
|
|
ptx = (float)tmp[0]; pty = (float)tmp[1]; ptz = (float)tmp[2];
|
|
|
|
|
|
|
|
switch (m_nCurAction)
|
|
|
|
{
|
|
|
|
case LC_ACTION_SELECT:
|
|
|
|
{
|
|
|
|
int ptx = x, pty = y;
|
|
|
|
|
|
|
|
if (ptx >= viewport[0] + viewport[2])
|
|
|
|
ptx = viewport[0] + viewport[2] - 1;
|
|
|
|
else if (ptx <= viewport[0])
|
|
|
|
ptx = viewport[0] + 1;
|
|
|
|
|
|
|
|
if (pty >= viewport[1] + viewport[3])
|
|
|
|
pty = viewport[1] + viewport[3] - 1;
|
|
|
|
else if (pty <= viewport[1])
|
|
|
|
pty = viewport[1] + 1;
|
|
|
|
|
|
|
|
m_fTrack[0] = (float)ptx;
|
|
|
|
m_fTrack[1] = (float)pty;
|
|
|
|
|
|
|
|
UpdateAllViews();
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case LC_ACTION_INSERT:
|
|
|
|
{
|
|
|
|
if (m_nDownX != x || m_nDownY != y)
|
|
|
|
{
|
|
|
|
m_nDownX = x;
|
|
|
|
m_nDownY = y;
|
|
|
|
|
|
|
|
UpdateAllViews();
|
|
|
|
}
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case LC_ACTION_SPOTLIGHT:
|
|
|
|
{
|
|
|
|
float mouse = 10.0f/(21 - m_nMouse);
|
|
|
|
float delta[3] = { (ptx - m_fTrack[0])*mouse,
|
|
|
|
(pty - m_fTrack[1])*mouse, (ptz - m_fTrack[2])*mouse };
|
|
|
|
|
|
|
|
m_fTrack[0] = ptx;
|
|
|
|
m_fTrack[1] = pty;
|
|
|
|
m_fTrack[2] = ptz;
|
|
|
|
|
|
|
|
Light* pLight = m_pLights;
|
|
|
|
|
|
|
|
pLight->Move (1, m_bAnimation, false, delta[0], delta[1], delta[2]);
|
|
|
|
pLight->UpdatePosition (1, m_bAnimation);
|
|
|
|
|
|
|
|
SystemUpdateFocus(NULL);
|
|
|
|
UpdateAllViews();
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case LC_ACTION_CAMERA:
|
|
|
|
{
|
|
|
|
float mouse = 10.0f/(21 - m_nMouse);
|
|
|
|
float delta[3] = { (ptx - m_fTrack[0])*mouse,
|
|
|
|
(pty - m_fTrack[1])*mouse, (ptz - m_fTrack[2])*mouse };
|
|
|
|
|
|
|
|
m_fTrack[0] = ptx;
|
|
|
|
m_fTrack[1] = pty;
|
|
|
|
m_fTrack[2] = ptz;
|
|
|
|
|
|
|
|
Camera* pCamera = m_pCameras;
|
|
|
|
while (pCamera->m_pNext != NULL)
|
|
|
|
pCamera = pCamera->m_pNext;
|
|
|
|
|
|
|
|
pCamera->Move (1, m_bAnimation, false, delta[0], delta[1], delta[2]);
|
|
|
|
pCamera->UpdatePosition(1, m_bAnimation);
|
|
|
|
|
|
|
|
SystemUpdateFocus(NULL);
|
|
|
|
UpdateAllViews();
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case LC_ACTION_MOVE:
|
|
|
|
{
|
|
|
|
// Check if the mouse moved since the last update.
|
|
|
|
if ((x == m_nDownX) && (y == m_nDownY))
|
|
|
|
break;
|
|
|
|
|
|
|
|
Camera* Camera = m_pViewCameras[m_nActiveViewport];
|
|
|
|
bool Redraw;
|
|
|
|
|
|
|
|
if ((m_OverlayActive && (m_OverlayMode != LC_OVERLAY_XYZ)) || (!Camera->IsSide()))
|
|
|
|
{
|
|
|
|
Vector3 ScreenX = Cross3(Camera->GetTargetPosition() - Camera->GetEyePosition(), Camera->GetUpVector());
|
|
|
|
Vector3 ScreenY = Camera->GetUpVector();
|
|
|
|
ScreenX.Normalize();
|
|
|
|
Vector3 Dir1, Dir2;
|
|
|
|
bool SingleDir = true;
|
|
|
|
|
|
|
|
int OverlayMode;
|
|
|
|
|
|
|
|
if (m_OverlayActive && (m_OverlayMode != LC_OVERLAY_XYZ))
|
|
|
|
OverlayMode = m_OverlayMode;
|
|
|
|
else if (m_nTracking == LC_TRACK_LEFT)
|
|
|
|
OverlayMode = LC_OVERLAY_XY;
|
|
|
|
else
|
|
|
|
OverlayMode = LC_OVERLAY_Z;
|
|
|
|
|
|
|
|
switch (OverlayMode)
|
|
|
|
{
|
|
|
|
case LC_OVERLAY_X:
|
|
|
|
Dir1 = Vector3(1, 0, 0);
|
|
|
|
break;
|
|
|
|
case LC_OVERLAY_Y:
|
|
|
|
Dir1 = Vector3(0, 1, 0);
|
|
|
|
break;
|
|
|
|
case LC_OVERLAY_Z:
|
|
|
|
Dir1 = Vector3(0, 0, 1);
|
|
|
|
break;
|
|
|
|
case LC_OVERLAY_XY:
|
|
|
|
Dir1 = Vector3(1, 0, 0);
|
|
|
|
Dir2 = Vector3(0, 1, 0);
|
|
|
|
SingleDir = false;
|
|
|
|
break;
|
|
|
|
case LC_OVERLAY_XZ:
|
|
|
|
Dir1 = Vector3(1, 0, 0);
|
|
|
|
Dir2 = Vector3(0, 0, 1);
|
|
|
|
SingleDir = false;
|
|
|
|
break;
|
|
|
|
case LC_OVERLAY_YZ:
|
|
|
|
Dir1 = Vector3(0, 1, 0);
|
|
|
|
Dir2 = Vector3(0, 0, 1);
|
|
|
|
SingleDir = false;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Transform the translation axis.
|
|
|
|
Vector3 Axis1 = Dir1;
|
|
|
|
Vector3 Axis2 = Dir2;
|
|
|
|
|
|
|
|
if ((m_nSnap & LC_DRAW_GLOBAL_SNAP) == 0)
|
|
|
|
{
|
|
|
|
Object* Focus = GetFocusObject();
|
|
|
|
|
|
|
|
if ((Focus != NULL) && Focus->IsPiece())
|
|
|
|
{
|
|
|
|
float Rot[4];
|
|
|
|
((Piece*)Focus)->GetRotation(Rot);
|
|
|
|
|
|
|
|
Matrix33 RotMat;
|
|
|
|
RotMat.CreateFromAxisAngle(Vector3(Rot[0], Rot[1], Rot[2]), Rot[3] * LC_DTOR);
|
|
|
|
|
|
|
|
Axis1 = Mul(Dir1, RotMat);
|
|
|
|
Axis2 = Mul(Dir2, RotMat);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Find out what direction the mouse is going to move stuff.
|
|
|
|
Vector3 MoveX, MoveY;
|
|
|
|
|
|
|
|
if (SingleDir)
|
|
|
|
{
|
|
|
|
float dx1 = Dot3(ScreenX, Axis1);
|
|
|
|
float dy1 = Dot3(ScreenY, Axis1);
|
|
|
|
|
|
|
|
if (fabsf(dx1) > fabsf(dy1))
|
|
|
|
{
|
|
|
|
if (dx1 >= 0.0f)
|
|
|
|
MoveX = Dir1;
|
|
|
|
else
|
|
|
|
MoveX = -Dir1;
|
|
|
|
|
|
|
|
MoveY = Vector3(0, 0, 0);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
MoveX = Vector3(0, 0, 0);
|
|
|
|
|
|
|
|
if (dy1 > 0.0f)
|
|
|
|
MoveY = Dir1;
|
|
|
|
else
|
|
|
|
MoveY = -Dir1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
float dx1 = Dot3(ScreenX, Axis1);
|
|
|
|
float dy1 = Dot3(ScreenY, Axis1);
|
|
|
|
float dx2 = Dot3(ScreenX, Axis2);
|
|
|
|
float dy2 = Dot3(ScreenY, Axis2);
|
|
|
|
|
|
|
|
if (fabsf(dx1) > fabsf(dx2))
|
|
|
|
{
|
|
|
|
if (dx1 >= 0.0f)
|
|
|
|
MoveX = Dir1;
|
|
|
|
else
|
|
|
|
MoveX = -Dir1;
|
|
|
|
|
|
|
|
if (dy2 >= 0.0f)
|
|
|
|
MoveY = Dir2;
|
|
|
|
else
|
|
|
|
MoveY = -Dir2;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (dx2 >= 0.0f)
|
|
|
|
MoveX = Dir2;
|
|
|
|
else
|
|
|
|
MoveX = -Dir2;
|
|
|
|
|
|
|
|
if (dy1 > 0.0f)
|
|
|
|
MoveY = Dir1;
|
|
|
|
else
|
|
|
|
MoveY = -Dir1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
MoveX *= (float)(x - m_nDownX) * 0.25f / (21 - m_nMouse);
|
|
|
|
MoveY *= (float)(y - m_nDownY) * 0.25f / (21 - m_nMouse);
|
|
|
|
|
|
|
|
m_nDownX = x;
|
|
|
|
m_nDownY = y;
|
|
|
|
|
|
|
|
Vector3 Delta = MoveX + MoveY + m_MouseSnapLeftover;
|
|
|
|
Redraw = MoveSelectedObjects(Delta, m_MouseSnapLeftover, true);
|
|
|
|
m_MouseTotalDelta += Delta;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// 3D movement.
|
|
|
|
Vector3 ScreenZ = (Camera->GetTargetPosition() - Camera->GetEyePosition()).Normalize();
|
|
|
|
Vector3 ScreenX = Cross3(ScreenZ, Camera->GetUpVector());
|
|
|
|
Vector3 ScreenY = Camera->GetUpVector();
|
|
|
|
|
|
|
|
Vector3 TotalMove;
|
|
|
|
|
|
|
|
if (m_nTracking == LC_TRACK_LEFT)
|
|
|
|
{
|
|
|
|
Vector3 MoveX, MoveY;
|
|
|
|
|
|
|
|
MoveX = ScreenX * (float)(x - m_nDownX) * 0.25f / (float)(21 - m_nMouse);
|
|
|
|
MoveY = ScreenY * (float)(y - m_nDownY) * 0.25f / (float)(21 - m_nMouse);
|
|
|
|
|
|
|
|
TotalMove = MoveX + MoveY + m_MouseSnapLeftover;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
Vector3 MoveZ;
|
|
|
|
|
|
|
|
MoveZ = ScreenZ * (float)(y - m_nDownY) * 0.25f / (float)(21 - m_nMouse);
|
|
|
|
|
|
|
|
TotalMove = MoveZ + m_MouseSnapLeftover;
|
|
|
|
}
|
|
|
|
|
|
|
|
m_nDownX = x;
|
|
|
|
m_nDownY = y;
|
|
|
|
|
|
|
|
Redraw = MoveSelectedObjects(TotalMove, m_MouseSnapLeftover, true);
|
|
|
|
}
|
|
|
|
|
|
|
|
SystemUpdateFocus(NULL);
|
|
|
|
if (Redraw)
|
|
|
|
UpdateAllViews();
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case LC_ACTION_ROTATE:
|
|
|
|
{
|
|
|
|
Camera* Camera = m_pViewCameras[m_nActiveViewport];
|
|
|
|
bool Redraw;
|
|
|
|
|
|
|
|
if ((m_OverlayActive && (m_OverlayMode != LC_OVERLAY_XYZ)) || (!Camera->IsSide()))
|
|
|
|
{
|
|
|
|
Vector3 ScreenX = Cross3(Camera->GetTargetPosition() - Camera->GetEyePosition(), Camera->GetUpVector());
|
|
|
|
Vector3 ScreenY = Camera->GetUpVector();
|
|
|
|
ScreenX.Normalize();
|
|
|
|
Vector3 Dir1, Dir2;
|
|
|
|
bool SingleDir = true;
|
|
|
|
|
|
|
|
int OverlayMode;
|
|
|
|
|
|
|
|
if (m_OverlayActive && (m_OverlayMode != LC_OVERLAY_XYZ))
|
|
|
|
OverlayMode = m_OverlayMode;
|
|
|
|
else if (m_nTracking == LC_TRACK_LEFT)
|
|
|
|
OverlayMode = LC_OVERLAY_XY;
|
|
|
|
else
|
|
|
|
OverlayMode = LC_OVERLAY_Z;
|
|
|
|
|
|
|
|
switch (OverlayMode)
|
|
|
|
{
|
|
|
|
case LC_OVERLAY_X:
|
|
|
|
Dir1 = Vector3(1, 0, 0);
|
|
|
|
break;
|
|
|
|
case LC_OVERLAY_Y:
|
|
|
|
Dir1 = Vector3(0, 1, 0);
|
|
|
|
break;
|
|
|
|
case LC_OVERLAY_Z:
|
|
|
|
Dir1 = Vector3(0, 0, 1);
|
|
|
|
break;
|
|
|
|
case LC_OVERLAY_XY:
|
|
|
|
Dir1 = Vector3(1, 0, 0);
|
|
|
|
Dir2 = Vector3(0, 1, 0);
|
|
|
|
SingleDir = false;
|
|
|
|
break;
|
|
|
|
case LC_OVERLAY_XZ:
|
|
|
|
Dir1 = Vector3(1, 0, 0);
|
|
|
|
Dir2 = Vector3(0, 0, 1);
|
|
|
|
SingleDir = false;
|
|
|
|
break;
|
|
|
|
case LC_OVERLAY_YZ:
|
|
|
|
Dir1 = Vector3(0, 1, 0);
|
|
|
|
Dir2 = Vector3(0, 0, 1);
|
|
|
|
SingleDir = false;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Find out what direction the mouse is going to move stuff.
|
|
|
|
Vector3 MoveX, MoveY;
|
|
|
|
|
|
|
|
if (SingleDir)
|
|
|
|
{
|
|
|
|
float dx1 = Dot3(ScreenX, Dir1);
|
|
|
|
float dy1 = Dot3(ScreenY, Dir1);
|
|
|
|
|
|
|
|
if (fabsf(dx1) > fabsf(dy1))
|
|
|
|
{
|
|
|
|
if (dx1 >= 0.0f)
|
|
|
|
MoveX = Dir1;
|
|
|
|
else
|
|
|
|
MoveX = -Dir1;
|
|
|
|
|
|
|
|
MoveY = Vector3(0, 0, 0);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
MoveX = Vector3(0, 0, 0);
|
|
|
|
|
|
|
|
if (dy1 > 0.0f)
|
|
|
|
MoveY = Dir1;
|
|
|
|
else
|
|
|
|
MoveY = -Dir1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
float dx1 = Dot3(ScreenX, Dir1);
|
|
|
|
float dy1 = Dot3(ScreenY, Dir1);
|
|
|
|
float dx2 = Dot3(ScreenX, Dir2);
|
|
|
|
float dy2 = Dot3(ScreenY, Dir2);
|
|
|
|
|
|
|
|
if (fabsf(dx1) > fabsf(dx2))
|
|
|
|
{
|
|
|
|
if (dx1 >= 0.0f)
|
|
|
|
MoveX = Dir1;
|
|
|
|
else
|
|
|
|
MoveX = -Dir1;
|
|
|
|
|
|
|
|
if (dy2 >= 0.0f)
|
|
|
|
MoveY = Dir2;
|
|
|
|
else
|
|
|
|
MoveY = -Dir2;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (dx2 >= 0.0f)
|
|
|
|
MoveX = Dir2;
|
|
|
|
else
|
|
|
|
MoveX = -Dir2;
|
|
|
|
|
|
|
|
if (dy1 > 0.0f)
|
|
|
|
MoveY = Dir1;
|
|
|
|
else
|
|
|
|
MoveY = -Dir1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
MoveX *= (float)(x - m_nDownX) * 36.0f / (21 - m_nMouse);
|
|
|
|
MoveY *= (float)(y - m_nDownY) * 36.0f / (21 - m_nMouse);
|
|
|
|
|
|
|
|
m_nDownX = x;
|
|
|
|
m_nDownY = y;
|
|
|
|
|
|
|
|
Vector3 Delta = MoveX + MoveY + m_MouseSnapLeftover;
|
|
|
|
Redraw = RotateSelectedObjects(Delta, m_MouseSnapLeftover);
|
|
|
|
m_MouseTotalDelta += Delta;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// 3D movement.
|
|
|
|
Vector3 ScreenZ = (Camera->GetTargetPosition() - Camera->GetEyePosition()).Normalize();
|
|
|
|
Vector3 ScreenX = Cross3(ScreenZ, Camera->GetUpVector());
|
|
|
|
Vector3 ScreenY = Camera->GetUpVector();
|
|
|
|
|
|
|
|
Vector3 Delta;
|
|
|
|
|
|
|
|
if (m_nTracking == LC_TRACK_LEFT)
|
|
|
|
{
|
|
|
|
Vector3 MoveX, MoveY;
|
|
|
|
|
|
|
|
MoveX = ScreenX * (float)(x - m_nDownX) * 36.0f / (float)(21 - m_nMouse);
|
|
|
|
MoveY = ScreenY * (float)(y - m_nDownY) * 36.0f / (float)(21 - m_nMouse);
|
|
|
|
|
|
|
|
Delta = MoveX + MoveY + m_MouseSnapLeftover;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
Vector3 MoveZ;
|
|
|
|
|
|
|
|
MoveZ = ScreenZ * (float)(y - m_nDownY) * 36.0f / (float)(21 - m_nMouse);
|
|
|
|
|
|
|
|
Delta = MoveZ + m_MouseSnapLeftover;
|
|
|
|
}
|
|
|
|
|
|
|
|
m_nDownX = x;
|
|
|
|
m_nDownY = y;
|
|
|
|
|
|
|
|
Redraw = RotateSelectedObjects(Delta, m_MouseSnapLeftover);
|
|
|
|
m_MouseTotalDelta += Delta;
|
|
|
|
}
|
|
|
|
|
|
|
|
SystemUpdateFocus(NULL);
|
|
|
|
if (Redraw)
|
|
|
|
UpdateAllViews();
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case LC_ACTION_ZOOM:
|
|
|
|
{
|
|
|
|
if (m_nDownY == y)
|
|
|
|
break;
|
|
|
|
|
|
|
|
m_pViewCameras[m_nActiveViewport]->DoZoom(y - m_nDownY, m_nMouse, m_bAnimation ? m_nCurFrame : m_nCurStep, m_bAnimation, m_bAddKeys);
|
|
|
|
m_nDownY = y;
|
|
|
|
SystemUpdateFocus(NULL);
|
|
|
|
UpdateAllViews();
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case LC_ACTION_ZOOM_REGION:
|
|
|
|
{
|
|
|
|
if ((m_nDownY == y) && (m_nDownX == x))
|
|
|
|
break;
|
|
|
|
|
|
|
|
m_nDownX = x;
|
|
|
|
m_nDownY = y;
|
|
|
|
UpdateAllViews();
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case LC_ACTION_PAN:
|
|
|
|
{
|
|
|
|
if ((m_nDownY == y) && (m_nDownX == x))
|
|
|
|
break;
|
|
|
|
|
|
|
|
m_pViewCameras[m_nActiveViewport]->DoPan(x - m_nDownX, y - m_nDownY, m_nMouse, m_bAnimation ? m_nCurFrame : m_nCurStep, m_bAnimation, m_bAddKeys);
|
|
|
|
m_nDownX = x;
|
|
|
|
m_nDownY = y;
|
|
|
|
SystemUpdateFocus(NULL);
|
|
|
|
UpdateAllViews();
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case LC_ACTION_ROTATE_VIEW:
|
|
|
|
{
|
|
|
|
if ((m_nDownY == y) && (m_nDownX == x))
|
|
|
|
break;
|
|
|
|
|
|
|
|
// We can't rotate the side cameras.
|
|
|
|
if (m_pViewCameras[m_nActiveViewport]->IsSide())
|
|
|
|
{
|
|
|
|
float eye[3], target[3], up[3];
|
|
|
|
m_pViewCameras[m_nActiveViewport]->GetEyePos(eye);
|
|
|
|
m_pViewCameras[m_nActiveViewport]->GetTargetPos(target);
|
|
|
|
m_pViewCameras[m_nActiveViewport]->GetUpVec(up);
|
|
|
|
Camera* pCamera = new Camera(eye, target, up, m_pCameras);
|
|
|
|
|
|
|
|
m_pViewCameras[m_nActiveViewport] = pCamera;
|
|
|
|
SystemUpdateCameraMenu(m_pCameras);
|
|
|
|
SystemUpdateCurrentCamera(NULL, pCamera, m_pCameras);
|
|
|
|
}
|
|
|
|
|
|
|
|
float bs[6] = { 10000, 10000, 10000, -10000, -10000, -10000 };
|
|
|
|
for (Piece* pPiece = m_pPieces; pPiece; pPiece = pPiece->m_pNext)
|
|
|
|
if (pPiece->IsSelected())
|
|
|
|
pPiece->CompareBoundingBox(bs);
|
|
|
|
bs[0] = (bs[0]+bs[3])/2;
|
|
|
|
bs[1] = (bs[1]+bs[4])/2;
|
|
|
|
bs[2] = (bs[2]+bs[5])/2;
|
|
|
|
|
|
|
|
switch (m_OverlayMode)
|
|
|
|
{
|
|
|
|
case LC_OVERLAY_XYZ:
|
|
|
|
m_pViewCameras[m_nActiveViewport]->DoRotate(x - m_nDownX, y - m_nDownY, m_nMouse, m_bAnimation ? m_nCurFrame : m_nCurStep, m_bAnimation, m_bAddKeys, bs);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case LC_OVERLAY_X:
|
|
|
|
m_pViewCameras[m_nActiveViewport]->DoRotate(x - m_nDownX, 0, m_nMouse, m_bAnimation ? m_nCurFrame : m_nCurStep, m_bAnimation, m_bAddKeys, bs);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case LC_OVERLAY_Y:
|
|
|
|
m_pViewCameras[m_nActiveViewport]->DoRotate(0, y - m_nDownY, m_nMouse, m_bAnimation ? m_nCurFrame : m_nCurStep, m_bAnimation, m_bAddKeys, bs);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case LC_OVERLAY_Z:
|
|
|
|
m_pViewCameras[m_nActiveViewport]->DoRoll(x - m_nDownX, m_nMouse, m_bAnimation ? m_nCurFrame : m_nCurStep, m_bAnimation, m_bAddKeys);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
m_nDownX = x;
|
|
|
|
m_nDownY = y;
|
|
|
|
SystemUpdateFocus(NULL);
|
|
|
|
UpdateAllViews();
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case LC_ACTION_ROLL:
|
|
|
|
{
|
|
|
|
if (m_nDownX == x)
|
|
|
|
break;
|
|
|
|
|
|
|
|
m_pViewCameras[m_nActiveViewport]->DoRoll(x - m_nDownX, m_nMouse, m_bAnimation ? m_nCurFrame : m_nCurStep, m_bAnimation, m_bAddKeys);
|
|
|
|
m_nDownX = x;
|
|
|
|
SystemUpdateFocus(NULL);
|
|
|
|
UpdateAllViews();
|
|
|
|
} break;
|
|
|
|
/*
|
|
|
|
case LC_ACTION_CURVE:
|
|
|
|
{
|
|
|
|
float mouse = 10.0f/(21 - m_nMouse);
|
|
|
|
float dx = (ptx - m_fTrack[0])*mouse;
|
|
|
|
float dy = (pty - m_fTrack[1])*mouse;
|
|
|
|
float dz = (ptz - m_fTrack[2])*mouse;
|
|
|
|
Object *pObj = NULL;
|
|
|
|
Curve *pCurve;
|
|
|
|
|
|
|
|
m_fTrack[0] = ptx;
|
|
|
|
m_fTrack[1] = pty;
|
|
|
|
m_fTrack[2] = ptz;
|
|
|
|
|
|
|
|
for (pObj = m_pObjects; pObj != NULL; pObj = pObj->m_pNext)
|
|
|
|
if (pObj->IsSelected ())
|
|
|
|
break;
|
|
|
|
|
|
|
|
if (pObj == NULL)
|
|
|
|
break;
|
|
|
|
pCurve = (Curve*)pObj;
|
|
|
|
|
|
|
|
pCurve->Move (1, m_bAnimation, false, dx, dy, dz);
|
|
|
|
pCurve->UpdatePosition(1, m_bAnimation);
|
|
|
|
|
|
|
|
SystemUpdateFocus(NULL);
|
|
|
|
UpdateAllViews();
|
|
|
|
} break;
|
|
|
|
*/
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check if the mouse is over a different area of the overlay and redraw it.
|
|
|
|
void Project::MouseUpdateOverlays(int x, int y)
|
|
|
|
{
|
|
|
|
const float OverlayScale = m_OverlayScale[m_nActiveViewport];
|
|
|
|
|
|
|
|
if (m_nCurAction == LC_ACTION_MOVE)
|
|
|
|
{
|
|
|
|
const float OverlayMoveArrowSize = 1.5f;
|
|
|
|
|
|
|
|
Matrix44 ModelView, Projection;
|
|
|
|
int Viewport[4];
|
|
|
|
|
|
|
|
GetActiveViewportMatrices(ModelView, Projection, Viewport);
|
|
|
|
|
|
|
|
// Array of points for the arrow edges.
|
|
|
|
Vector3 Points[4] =
|
|
|
|
{
|
|
|
|
Vector3(m_OverlayCenter[0], m_OverlayCenter[1], m_OverlayCenter[2]),
|
|
|
|
Vector3(OverlayMoveArrowSize * OverlayScale, 0, 0),
|
|
|
|
Vector3(0, OverlayMoveArrowSize * OverlayScale, 0),
|
|
|
|
Vector3(0, 0, OverlayMoveArrowSize * OverlayScale),
|
|
|
|
};
|
|
|
|
|
|
|
|
// Find the rotation from the focused piece if relative snap is enabled.
|
|
|
|
if ((m_nSnap & LC_DRAW_GLOBAL_SNAP) == 0)
|
|
|
|
{
|
|
|
|
Object* Focus = GetFocusObject();
|
|
|
|
|
|
|
|
if ((Focus != NULL) && Focus->IsPiece())
|
|
|
|
{
|
|
|
|
float Rot[4];
|
|
|
|
((Piece*)Focus)->GetRotation(Rot);
|
|
|
|
|
|
|
|
Matrix33 RotMat;
|
|
|
|
RotMat.CreateFromAxisAngle(Vector3(Rot[0], Rot[1], Rot[2]), Rot[3] * LC_DTOR);
|
|
|
|
|
|
|
|
for (int i = 1; i < 4; i++)
|
|
|
|
Points[i] = Mul(Points[i], RotMat);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int i, Mode = -1;
|
|
|
|
Vector3 Pt((float)x, (float)y, 0);
|
|
|
|
|
|
|
|
for (i = 1; i < 4; i++)
|
|
|
|
Points[i] += Points[0];
|
|
|
|
|
|
|
|
ProjectPoints(Points, 4, ModelView, Projection, Viewport);
|
|
|
|
|
|
|
|
// Check if the mouse is over an arrow.
|
|
|
|
for (i = 1; i < 4; i++)
|
|
|
|
{
|
|
|
|
Vector3 Line = Points[i] - Points[0];
|
|
|
|
Vector3 Vec = Pt - Points[0];
|
|
|
|
|
|
|
|
float u = Dot3(Vec, Line) / Line.LengthSquared();
|
|
|
|
|
|
|
|
// Point is outside the line segment.
|
|
|
|
if (u < 0.0f || u > 1.0f)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
// Closest point in the line segment to the mouse.
|
|
|
|
Vector3 Closest = Points[0] + u * Line;
|
|
|
|
|
|
|
|
if ((Closest - Pt).LengthSquared() < 100.0f)
|
|
|
|
{
|
|
|
|
// If we already know the mouse is close to another axis, select a plane.
|
|
|
|
if (Mode != -1)
|
|
|
|
{
|
|
|
|
if (Mode == LC_OVERLAY_X)
|
|
|
|
{
|
|
|
|
if (i == 2)
|
|
|
|
{
|
|
|
|
Mode = LC_OVERLAY_XY;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
Mode = LC_OVERLAY_XZ;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
Mode = LC_OVERLAY_YZ;
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
Mode = LC_OVERLAY_X + i - 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Mode == -1)
|
|
|
|
{
|
|
|
|
Mode = LC_OVERLAY_XYZ;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Mode != m_OverlayMode)
|
|
|
|
{
|
|
|
|
m_OverlayMode = Mode;
|
|
|
|
UpdateAllViews();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (m_nCurAction == LC_ACTION_ROTATE)
|
|
|
|
{
|
|
|
|
const float OverlayRotateRadius = 2.0f;
|
|
|
|
|
|
|
|
// Calculate the distance from the mouse pointer to the center of the sphere.
|
|
|
|
GLdouble px, py, pz, rx, ry, rz;
|
|
|
|
GLdouble ModelMatrix[16], ProjMatrix[16];
|
|
|
|
GLint Viewport[4];
|
|
|
|
|
|
|
|
LoadViewportProjection(m_nActiveViewport);
|
|
|
|
glGetDoublev(GL_MODELVIEW_MATRIX, ModelMatrix);
|
|
|
|
glGetDoublev(GL_PROJECTION_MATRIX, ProjMatrix);
|
|
|
|
glGetIntegerv(GL_VIEWPORT, Viewport);
|
|
|
|
|
|
|
|
// Unproject the mouse point against both the front and the back clipping planes.
|
|
|
|
gluUnProject(x, y, 0, ModelMatrix, ProjMatrix, Viewport, &px, &py, &pz);
|
|
|
|
gluUnProject(x, y, 1, ModelMatrix, ProjMatrix, Viewport, &rx, &ry, &rz);
|
|
|
|
|
|
|
|
Vector3 SegStart((float)rx, (float)ry, (float)rz);
|
|
|
|
Vector3 SegEnd((float)px, (float)py, (float)pz);
|
|
|
|
Vector3 Center(m_OverlayCenter[0], m_OverlayCenter[1], m_OverlayCenter[2]);
|
|
|
|
|
|
|
|
Vector3 Line = SegEnd - SegStart;
|
|
|
|
Vector3 Vec = Center - SegStart;
|
|
|
|
|
|
|
|
float u = Dot3(Vec, Line) / Line.LengthSquared();
|
|
|
|
|
|
|
|
// Closest point in the line to the mouse.
|
|
|
|
Vector3 Closest = SegStart + u * Line;
|
|
|
|
|
|
|
|
int Mode = -1;
|
|
|
|
float Distance = (Closest - Center).Length();
|
|
|
|
const float Epsilon = 0.25f * OverlayScale;
|
|
|
|
|
|
|
|
if (Distance > (OverlayRotateRadius * OverlayScale + Epsilon))
|
|
|
|
{
|
|
|
|
Mode = LC_OVERLAY_XYZ;
|
|
|
|
}
|
|
|
|
else if (Distance < (OverlayRotateRadius * OverlayScale + Epsilon))
|
|
|
|
{
|
|
|
|
// 3D rotation unless we're over one of the axis circles.
|
|
|
|
Mode = LC_OVERLAY_XYZ;
|
|
|
|
|
|
|
|
// Point P on a line defined by two points P1 and P2 is described by P = P1 + u (P2 - P1)
|
|
|
|
// A sphere centered at P3 with radius r is described by (x - x3)^2 + (y - y3)^2 + (z - z3)^2 = r^2
|
|
|
|
// Substituting the equation of the line into the sphere gives a quadratic equation where:
|
|
|
|
// a = (x2 - x1)^2 + (y2 - y1)^2 + (z2 - z1)^2
|
|
|
|
// b = 2[ (x2 - x1) (x1 - x3) + (y2 - y1) (y1 - y3) + (z2 - z1) (z1 - z3) ]
|
|
|
|
// c = x32 + y32 + z32 + x12 + y12 + z12 - 2[x3 x1 + y3 y1 + z3 z1] - r2
|
|
|
|
// The solutions to this quadratic are described by: (-b +- sqrt(b^2 - 4 a c) / 2 a
|
|
|
|
// The exact behavior is determined by b^2 - 4 a c:
|
|
|
|
// If this is less than 0 then the line does not intersect the sphere.
|
|
|
|
// If it equals 0 then the line is a tangent to the sphere intersecting it at one point
|
|
|
|
// If it is greater then 0 the line intersects the sphere at two points.
|
|
|
|
|
|
|
|
float x1 = (float)px, y1 = (float)py, z1 = (float)pz;
|
|
|
|
float x2 = (float)rx, y2 = (float)ry, z2 = (float)rz;
|
|
|
|
float x3 = m_OverlayCenter[0], y3 = m_OverlayCenter[1], z3 = m_OverlayCenter[2];
|
|
|
|
float r = OverlayRotateRadius * OverlayScale;
|
|
|
|
|
|
|
|
// TODO: rewrite using vectors.
|
|
|
|
float a = (x2 - x1)*(x2 - x1) + (y2 - y1)*(y2 - y1) + (z2 - z1)*(z2 - z1);
|
|
|
|
float b = 2 * ((x2 - x1)*(x1 - x3) + (y2 - y1)*(y1 - y3) + (z2 - z1)*(z1 - z3));
|
|
|
|
float c = x3*x3 + y3*y3 + z3*z3 + x1*x1 + y1*y1 + z1*z1 - 2*(x3*x1 + y3*y1 + z3*z1) - r*r;
|
|
|
|
float f = b * b - 4 * a * c;
|
|
|
|
|
|
|
|
if (f >= 0.0f)
|
|
|
|
{
|
|
|
|
Camera* Cam = m_pViewCameras[m_nActiveViewport];
|
|
|
|
Vector3 ViewDir = Cam->GetTargetPosition() - Cam->GetEyePosition();
|
|
|
|
|
|
|
|
float u1 = (-b + sqrtf(f)) / (2*a);
|
|
|
|
float u2 = (-b - sqrtf(f)) / (2*a);
|
|
|
|
|
|
|
|
Vector3 Intersections[2] =
|
|
|
|
{
|
|
|
|
Vector3(x1 + u1*(x2-x1), y1 + u1*(y2-y1), z1 + u1*(z2-z1)),
|
|
|
|
Vector3(x1 + u2*(x2-x1), y1 + u2*(y2-y1), z1 + u2*(z2-z1))
|
|
|
|
};
|
|
|
|
|
|
|
|
for (int i = 0; i < 2; i++)
|
|
|
|
{
|
|
|
|
Vector3 Dist = Intersections[i] - Center;
|
|
|
|
|
|
|
|
if (Dot3(ViewDir, Dist) > 0.0f)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
// Find the rotation from the focused piece if relative snap is enabled.
|
|
|
|
if ((m_nSnap & LC_DRAW_GLOBAL_SNAP) == 0)
|
|
|
|
{
|
|
|
|
Object* Focus = GetFocusObject();
|
|
|
|
|
|
|
|
if ((Focus != NULL) && Focus->IsPiece())
|
|
|
|
{
|
|
|
|
float Rot[4];
|
|
|
|
((Piece*)Focus)->GetRotation(Rot);
|
|
|
|
|
|
|
|
Matrix33 RotMat;
|
|
|
|
RotMat.CreateFromAxisAngle(Vector3(Rot[0], Rot[1], Rot[2]), -Rot[3] * LC_DTOR);
|
|
|
|
|
|
|
|
Dist = Mul(Dist, RotMat);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check if we're close enough to one of the axis.
|
|
|
|
Dist.Normalize();
|
|
|
|
|
|
|
|
float dx = fabsf(Dist[0]);
|
|
|
|
float dy = fabsf(Dist[1]);
|
|
|
|
float dz = fabsf(Dist[2]);
|
|
|
|
|
|
|
|
if (dx < dy)
|
|
|
|
{
|
|
|
|
if (dx < dz)
|
|
|
|
{
|
|
|
|
if (dx < Epsilon)
|
|
|
|
Mode = LC_OVERLAY_X;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (dz < Epsilon)
|
|
|
|
Mode = LC_OVERLAY_Z;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (dy < dz)
|
|
|
|
{
|
|
|
|
if (dy < Epsilon)
|
|
|
|
Mode = LC_OVERLAY_Y;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (dz < Epsilon)
|
|
|
|
Mode = LC_OVERLAY_Z;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Mode != LC_OVERLAY_XYZ)
|
|
|
|
{
|
|
|
|
switch (Mode)
|
|
|
|
{
|
|
|
|
case LC_OVERLAY_X:
|
|
|
|
Dist[0] = 0.0f;
|
|
|
|
break;
|
|
|
|
case LC_OVERLAY_Y:
|
|
|
|
Dist[1] = 0.0f;
|
|
|
|
break;
|
|
|
|
case LC_OVERLAY_Z:
|
|
|
|
Dist[2] = 0.0f;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
Dist *= r;
|
|
|
|
|
|
|
|
m_OverlayTrackStart = Center + Dist;
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Mode != m_OverlayMode)
|
|
|
|
{
|
|
|
|
m_OverlayMode = Mode;
|
|
|
|
UpdateAllViews();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (m_nCurAction == LC_ACTION_ROTATE_VIEW)
|
|
|
|
{
|
|
|
|
int vx, vy, vw, vh;
|
|
|
|
vx = (int)(viewports[m_nViewportMode].dim[m_nActiveViewport][0] * (float)m_nViewX);
|
|
|
|
vy = (int)(viewports[m_nViewportMode].dim[m_nActiveViewport][1] * (float)m_nViewY);
|
|
|
|
vw = (int)(viewports[m_nViewportMode].dim[m_nActiveViewport][2] * (float)m_nViewX);
|
|
|
|
vh = (int)(viewports[m_nViewportMode].dim[m_nActiveViewport][3] * (float)m_nViewY);
|
|
|
|
|
|
|
|
int cx = vx + vw / 2;
|
|
|
|
int cy = vy + vh / 2;
|
|
|
|
|
|
|
|
float d = sqrtf((float)((cx - x) * (cx - x) + (cy - y) * (cy - y)));
|
|
|
|
float r = min(vw, vh) * 0.35f;
|
|
|
|
|
|
|
|
const float SquareSize = max(8.0f, (vw+vh)/200);
|
|
|
|
|
|
|
|
if ((d < r + SquareSize) && (d > r - SquareSize))
|
|
|
|
{
|
|
|
|
if ((cx - x < SquareSize) && (cx - x > -SquareSize))
|
|
|
|
m_OverlayMode = LC_OVERLAY_Y;
|
|
|
|
|
|
|
|
if ((cy - y < SquareSize) && (cy - y > -SquareSize))
|
|
|
|
m_OverlayMode = LC_OVERLAY_X;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (d < r)
|
|
|
|
m_OverlayMode = LC_OVERLAY_XYZ;
|
|
|
|
else
|
|
|
|
m_OverlayMode = LC_OVERLAY_Z;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Project::ActivateOverlay()
|
|
|
|
{
|
|
|
|
if ((m_nCurAction == LC_ACTION_MOVE) || (m_nCurAction == LC_ACTION_ROTATE))
|
|
|
|
{
|
|
|
|
if (GetFocusPosition(m_OverlayCenter))
|
|
|
|
m_OverlayActive = true;
|
|
|
|
else if (GetSelectionCenter(m_OverlayCenter))
|
|
|
|
m_OverlayActive = true;
|
|
|
|
else
|
|
|
|
m_OverlayActive = false;
|
|
|
|
}
|
|
|
|
else if ((m_nCurAction == LC_ACTION_ZOOM_REGION) && (m_nTracking == LC_TRACK_START_LEFT))
|
|
|
|
m_OverlayActive = true;
|
|
|
|
else if (m_nCurAction == LC_ACTION_ROTATE_VIEW)
|
|
|
|
m_OverlayActive = true;
|
|
|
|
else
|
|
|
|
m_OverlayActive = false;
|
|
|
|
|
|
|
|
if (m_OverlayActive)
|
|
|
|
{
|
|
|
|
m_OverlayMode = LC_OVERLAY_XYZ;
|
|
|
|
UpdateOverlayScale();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Project::UpdateOverlayScale()
|
|
|
|
{
|
|
|
|
if (m_OverlayActive)
|
|
|
|
{
|
|
|
|
GLdouble ScreenX, ScreenY, ScreenZ, PointX, PointY, PointZ;
|
|
|
|
GLdouble ModelMatrix[16], ProjMatrix[16];
|
|
|
|
GLint Viewport[4];
|
|
|
|
|
|
|
|
for (int i = 0; i < viewports[m_nViewportMode].n; i++)
|
|
|
|
{
|
|
|
|
LoadViewportProjection(i);
|
|
|
|
glGetDoublev(GL_MODELVIEW_MATRIX, ModelMatrix);
|
|
|
|
glGetDoublev(GL_PROJECTION_MATRIX, ProjMatrix);
|
|
|
|
glGetIntegerv(GL_VIEWPORT, Viewport);
|
|
|
|
|
|
|
|
// Calculate the scaling factor by projecting the center to the front plane then
|
|
|
|
// projecting a point close to it back.
|
|
|
|
gluProject(m_OverlayCenter[0], m_OverlayCenter[1], m_OverlayCenter[2], ModelMatrix, ProjMatrix, Viewport, &ScreenX, &ScreenY, &ScreenZ);
|
|
|
|
gluUnProject(ScreenX + 10.0f, ScreenY, ScreenZ, ModelMatrix, ProjMatrix, Viewport, &PointX, &PointY, &PointZ);
|
|
|
|
|
|
|
|
Vector3 Dist((float)PointX - m_OverlayCenter[0], (float)PointY - m_OverlayCenter[1], (float)PointZ - m_OverlayCenter[2]);
|
|
|
|
m_OverlayScale[i] = Dist.Length() * 5.0f;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|