Note
Struttura
Costruzione di Interfacce
Lezione 28
Riordino e Scene Graph III
cignoni@iei.pi.cnr.it
http://vcg.iei.pi.cnr.it/~cignoni
Introduzione
Riordino e merge dei due progetti screen saver e editor in un unica soluzione.
Scene Graph design
Adattare lo scene graph
Riordiniamo
Facciamo un unica Soluzione con due progetti dentro, uno per l’editor e uno per il saver:
Partite dall’editor
Spostare le directory e i file
Mettete la sln nella root
lasciate il vcproj dove volete che vi faccia le dir debug/release (sotto editor)
cancellate e riaggiungete il progetto
Cancellate e riaggiungete tutti I file che si trovano in path relativi diversi
Aggiustate tutti I path degli include
Aggiungete lo screensaver
Riordiniamo
Cerchiamo di isolare quello che serve per disegnare l’anello dal resto della vista/doc
Alla fine solo il codice condiviso tra saver e editor è composto da:
Tutte le classi sotto vcg e sotto code
La classe moebiusstrip e le altre classi accessorie (pallina e movimento) derivate da CSGNode.
Sistemiamo lo screen Saver
Nello Screen saver dobbiamo
Aggiungere un oggetto globale
CSGMb Scene;
Creare una funz di inizializzazione
void CCISaverApp::Init(CString &name)
{
Scene.Clear();
if(name!="" && (00==name.Right(3).CompareNoCase("xml")))
{
XmlDoc xml;
  if(xml.read(LPCSTR (name) ))
{
Scene.root.XMLRead(xml.root(),&Scene);
Scene.m->Generate();
}
}
}
OnPaint
void CGLWnd::OnPaint()
{
CPaintDC dc(this); // device context for painting
SetGL();
glEnable(GL_LIGHTING);
glEnable(GL_NORMALIZE);
glEnable(GL_DEPTH_TEST);
glColor3f(1,1,1);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(60,aspect,.4,25);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(0,0,10,0,0,0,0,1,0); // World To Camera Transformation
Scene.root.glDraw(float(clock())/1000.0f);
SwapBuffers(m_hDC);
}
Screen saver
Modifichiamo l’interfaccia dello screen saver
Togliamo l’editbox
e aggiungiamo
un listbox
La configurazione dello screensaver consiste:
un elenco di nomi di file (pathname assoluti!) generati con l’editor.
Un indice che dice qual’e’ quello corrente
Interfaccia screen saver
Aggiungo I seguenti membri alla classe CCISaverDialog
vector<CString> m_names;
int m_select;
CListBox m_listSaver;
e alla classe CCISaverApp
vector<CString> names;
int Starting;
Leggiamo/Salviamo tutti questi dati nel registro
Read e write Settings
void CCISaverApp::ReadSetting()
{
names.clear();
int i=0;
bool ended=false;
while(!ended)
{
CString tmp;
CString buf; buf.Format("SaverName%03i",i);
tmp=GetProfileString("CISaver", buf, "");
if(tmp!=""){
names.push_back(tmp);
++i;
}
else  ended = true;
}
Starting=GetProfileInt("CISaver", "Starting", 0);
if(names.empty()) Init(CString());
else Init(names[Starting]);
}
WriteSetting
void CCISaverApp::WriteSetting()
{
for(int i=0;i<names.size();++i)
{
CString buf; buf.Format("SaverName%03i",i);
WriteProfileString("CISaver", buf, names[i]);
}
CString buf; buf.Format("SaverName%03i",i);
WriteProfileString("CISaver", buf, "");
WriteProfileInt("CISaver", "Starting", Starting);
}
DoSaverSetting
void CCISaverApp::DoSaverSetting(void)
{
CCISaverDlg dlg;
CString tok,cmdln=m_lpCmdLine;
   ReadSetting();
dlg.m_names=names;
dlg.m_select=Starting;
   m_pMainWnd = &dlg;
if (dlg.DoModal() == IDOK)
{
names=dlg.m_names;
Starting=dlg.m_select;
      WriteSetting();
}
Screen saver
Quando parte con il dialogo di configurazione l’app crea un oggetto dialogo, ne riempie alcune strutture con I parametri letti dal registro e passa il controllo al dialog (doModal)
Alla fine se l’utente ha premuto ok si copiano le strutture dati del dialog in quelle dell’app, si salvano nel registro e si esce.
On InitDialog
BOOL CCISaverDlg::OnInitDialog()
{
CDialog::OnInitDialog();
SetIcon(m_hIcon, TRUE); // Set big icon
SetIcon(m_hIcon, FALSE); // Set small icon
// Creazione finestra opengl
CRect rect;
GetDlgItem(IDC_IMAGE)->GetWindowRect(&rect);
ScreenToClient(&rect);
m_glwnd.myCreate(WS_EX_TOPMOST, WS_VISIBLE|WS_CHILD, rect, this, IDC_IMAGE);
// init del list box
for(unsigned i=0;i<m_names.size();++i){
CString buf=m_names[i];
int lastSlash=buf.ReverseFind('\\');
m_listSaver.AddString(buf.Right(buf.GetLength()-lastSlash-1));
}
    m_listSaver.SetCurSel(m_select);
return TRUE;  // return TRUE  unless you set the focus to a control
}
Gestione interfaccia
Nel dialogo dobbiamo gestire come eventi:
Aggiunta/cancellazione di un nome dal listbox
Selezione di un elemento nel box.
Nota l’elenco dei nomi dei file è tenuto in due posti
Nel list box (in forma abbreviata)
Nel vettore m_names
Add
void CCISaverDlg::OnBnClickedButtonBrowse()
{
 CFileDialog fd(true,"*.txt","test.txt");
 if(fd.DoModal()==IDOK) {
int pos=m_listSaver.FindStringExact(0,fd.GetFileName());
if(pos!=-1) AfxMessageBox("File già scelto!");
else{
m_names.push_back(fd.GetPathName());
int pos=m_listSaver.AddString(fd.GetFileName());
assert((pos+1)==m_names.size());
m_listSaver.SetCurSel(pos);
m_select=pos;
theApp.Init(m_names[pos]);
}
 };
}
Delete e update
void CCISaverDlg::OnBnClickedButtonDelete()
{
int pos=m_listSaver.GetCurSel();
m_names.erase(m_names.begin()+pos);
m_listSaver.DeleteString(pos);
}
void CCISaverDlg::OnLbnSelchangeListSaver()
{
m_select=m_listSaver.GetCurSel();
  theApp.Init(m_names[m_select]);
}
Finiamo di pulire doc/view
Aggiungiamo allo scene graph
Nodo Light
Nodi Trasformazioni
Nodo Texture
Come per le matrici hanno lo scope dei gruppi.
Nota in alcune situazioni potrebbe convenire fare gruppi che non chiudano lo scope per luci e texture.
"void CSGGroup::glDraw(const..."
void CSGGroup::glDraw(const float DocTime)
{
glPushMatrix();
  if(SaveLightState) glPushAttrib(GL_LIGHTING_BIT);
  iterator i;
for(i=Sons.begin();i!=Sons.end();++i)
(*i)->glDraw(DocTime);
if(SaveLightState) glPopAttrib();
glPopMatrix();
}
Nodo Light
class CSGLight :public CSGNode
{
public:
CSGLight(int id=0);
int Id;
Point4f Position;
Point4f AmbientColor;
Point4f DiffuseColor;
Point4f SpecularColor;
virtual void glDraw(const float DocTime);
virtual void XMLWrite(FILE *fp);
virtual void XMLRead(Xml &xml, CSG *Base);
};
Nodo Light
void  CSGLight::glDraw(const float DocTime)
{
glEnable(GL_LIGHT0+Id);
glLightfv(GL_LIGHT0+Id, GL_DIFFUSE,  DiffuseColor.V());
glLightfv(GL_LIGHT0+Id, GL_AMBIENT,  AmbientColor.V());
glLightfv(GL_LIGHT0+Id, GL_SPECULAR, SpecularColor.V());
glLightfv(GL_LIGHT0+Id, GL_POSITION, Position.V());
}
Nodo Light
class CSG
{
private:
int LightCounter;
public:
CSG(void);
~CSG(void);
CSGGroup root;
virtual CSGNode *Allocate(const string &classname);
virtual void Clear();
int Pick(int x, int y, const float &DocTime);
};
void CSG::Clear()
{
root.Clear();
LightCounter=0;
}
Nodo Light
CSGNode *CSG::Allocate(const string &classname)
{
CSGNode *pt=0;
if(classname=="CSGLight") pt= new CSGLight(LightCounter++);
  if(classname=="CSGGroup") pt= new CSGGroup;
  if(classname=="CSGRotation") pt= new CSGRotation;
  if(classname=="CSGTranslation") pt= new CSGTranslation;
  if(classname=="CSGTransformation") pt= new CSGTransformation;
  if(classname=="CSGAnimRotation") pt= new CSGAnimRotation;
  if(classname=="CSGAnimZPrecession") pt= new CSGAnimZPrecession;
return pt;
}
Nodo Light: Read e Write
void CSGLight::XMLWrite(FILE *fp)
{
fprintf(fp,"<CSGLight\n");
fprintf(fp,"DC0= \"%f\" DC1= \"%f\" DC2= \"%f\" DC3= \"%f\" \n",
DiffuseColor[0] ,DiffuseColor[1],DiffuseColor[2],DiffuseColor[3]);
fprintf(fp,"AC0= \"%f\" AC1= \"%f\" AC2= \"%f\" AC3= \"%f\" \n",
AmbientColor[0] ,AmbientColor[1],AmbientColor[2],AmbientColor[3]);
fprintf(fp,"SC0= \"%f\" SC1= \"%f\" SC2= \"%f\" SC3= \"%f\" \n",
SpecularColor[0],SpecularColor[1],SpecularColor[2],SpecularColor[3]);
fprintf(fp,"PT0= \"%f\" PT1= \"%f\" PT2= \"%f\" PT3= \"%f\" \n",
Position[0],     Position[1],Position[2],Position[3]);
fprintf(fp,"/>\n");
}
void CSGLight::XMLRead(Xml &xml, CSG *Base)
{
  assert(xml.id == "CSGLight");
  DiffuseColor[0]  = (float)atof(xml["DC0"].c_str()); DiffuseColor[1]  = (float)atof(xml["DC1"].c_str());
  AmbientColor[0]  = (float)atof(xml["AC0"].c_str()); AmbientColor[1]  = (float)atof(xml["AC1"].c_str());
  SpecularColor[0] = (float)atof(xml["SC0"].c_str()); SpecularColor[1] = (float)atof(xml["SC1"].c_str());
  Position[0]      = (float)atof(xml["PT0"].c_str()); Position[1]      = (float)atof(xml["PT1"].c_str());
  DiffuseColor[2]  = (float)atof(xml["DC2"].c_str());DiffuseColor[3]  = (float)atof(xml["DC3"].c_str());
  AmbientColor[2]  = (float)atof(xml["AC2"].c_str());AmbientColor[3]  = (float)atof(xml["AC3"].c_str());
  SpecularColor[2] = (float)atof(xml["SC2"].c_str());SpecularColor[3] = (float)atof(xml["SC3"].c_str());
  Position[2]      = (float)atof(xml["PT2"].c_str());Position[3]      = (float)atof(xml["PT3"].c_str());
}