r589: Added threaded rasterizer
[ctsim.git] / src / threadraster.cpp
1 /*****************************************************************************
2 ** FILE IDENTIFICATION
3 **
4 **   Name:          threadraster.cpp
5 **   Purpose:       Threaded rasterizer class
6 **   Programmer:    Kevin Rosenberg
7 **   Date Started:  February 2001
8 **
9 **  This is part of the CTSim program
10 **  Copyright (C) 1983-2001 Kevin Rosenberg
11 **
12 **  $Id: threadraster.cpp,v 1.1 2001/02/27 03:59:30 kevin Exp $
13 **
14 **  This program is free software; you can redistribute it and/or modify
15 **  it under the terms of the GNU General Public License (version 2) as
16 **  published by the Free Software Foundation.
17 **
18 **  This program is distributed in the hope that it will be useful,
19 **  but WITHOUT ANY WARRANTY; without even the implied warranty of
20 **  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21 **  GNU General Public License for more details.
22 **
23 **  You should have received a copy of the GNU General Public License
24 **  along with this program; if not, write to the Free Software
25 **  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
26 ******************************************************************************/
27
28 #include "wx/wxprec.h"
29
30 #ifndef WX_PRECOMP
31 #include "wx/wx.h"
32 #endif
33
34 #include "ct.h"
35 #include "ctsim.h"
36 #include "docs.h"
37 #include "views.h"
38 #include "threadraster.h"
39 #include "backgroundmgr.h"
40 #include "backgroundsupr.h"
41
42 #if defined(HAVE_CONFIG_H)
43 #include "config.h"
44 #endif
45
46
47
48 /////////////////////////////////////////////////////////////////////
49 //
50 // Class RasterizerSupervisorThread -- Thread for Background Supervisor
51 //
52 /////////////////////////////////////////////////////////////////////
53
54 RasterizerSupervisorThread::RasterizerSupervisorThread (PhantomFileView* pProjView, int iNX, int iNY, 
55    int iNSample, double dViewRatio, const char* const pszLabel)
56 : m_pPhantomView(pProjView), m_iNX(iNX), m_iNY(iNY), m_iNSample(iNSample), m_dViewRatio(dViewRatio), m_strLabel(pszLabel),
57   SupervisorThread()
58 {
59 }
60
61 wxThread::ExitCode
62 RasterizerSupervisorThread::Entry()
63 {
64   RasterizerSupervisor rasterSupervisor (this, m_pPhantomView, m_iNX, m_iNY, m_iNSample, m_dViewRatio, m_strLabel.c_str());
65
66   rasterSupervisor.start();
67   while (! rasterSupervisor.isDone() && ! rasterSupervisor.fail()) {
68     Sleep(100);
69     Yield();
70   }
71   if (rasterSupervisor.fail())
72   {
73     wxString msg ("Error starting Rasterizer supervisor: ");
74     msg += rasterSupervisor.getFailMessage().c_str();
75     msg += "\n";
76     wxCommandEvent eventLog (wxEVT_COMMAND_MENU_SELECTED, MAINMENU_LOG_EVENT );
77     eventLog.SetString( msg );
78     wxPostEvent( theApp->getMainFrame(), eventLog ); // send log event
79   }
80
81   while (! rasterSupervisor.workersDeleted()) {
82     Sleep(50);
83     rasterSupervisor.ProcessPendingEvents();
84   }
85
86   return reinterpret_cast<wxThread::ExitCode>(0);
87 }
88
89 void
90 RasterizerSupervisorThread::OnExit()
91 {
92 }
93
94
95 /////////////////////////////////////////////////////////////////////
96 //
97 // Class RasterizerSupervisor -- A Background Supervisor
98 //
99 /////////////////////////////////////////////////////////////////////
100
101 RasterizerSupervisor::RasterizerSupervisor (SupervisorThread* pThread, PhantomFileView* pPhantomView, int iNX, int iNY, 
102    int iNSample, double dViewRatio, const char* const pszLabel)
103     : m_pPhantomView(pPhantomView), m_pPhantomDoc(pPhantomView->GetDocument()), 
104       m_iNX(iNX), m_iNY(iNY), m_iNSample(iNSample), m_dViewRatio(dViewRatio), m_pszLabel(pszLabel), 
105       BackgroundSupervisor (pThread, pPhantomView->GetFrame(), pPhantomView->GetDocument(), "Rasterizing", iNX)
106 {
107   m_vecpChildImageFiles.reserve (getNumWorkers());
108   for (unsigned int iThread = 0; iThread < getNumWorkers(); iThread++) {
109     m_vecpChildImageFiles[iThread] = new ImageFile;
110   }
111
112
113
114 }
115
116 RasterizerSupervisor::~RasterizerSupervisor()
117 {
118   for (int i = 0; i < getNumWorkers(); i++)
119     delete m_vecpChildImageFiles[i];
120 }
121
122 BackgroundWorkerThread*
123 RasterizerSupervisor::createWorker (int iThread, int iStartUnit, int iNumUnits)
124 {
125    RasterizerWorker* pThread = new RasterizerWorker (this, iThread, iStartUnit, iNumUnits);
126    m_vecpChildImageFiles[iThread]->setArraySize (iNumUnits, m_iNY);
127    pThread->SetParameters (m_pPhantomView, m_vecpChildImageFiles[iThread], m_iNX, m_iNY, m_iNSample, m_dViewRatio);
128
129    return pThread;
130 }
131
132 void
133 RasterizerSupervisor::onDone()
134 {
135   wxCriticalSection doneSection;
136   wxCriticalSectionLocker critsect (doneSection);
137
138   ImageFileDocument* pImageDoc = theApp->newImageDoc();
139   if (! pImageDoc) {
140     sys_error (ERR_SEVERE, "Unable to create image file");
141     return;
142   }
143     
144   ImageFile* pImageFile = getImageFile();
145   pImageDoc->setImageFile (pImageFile);
146   if (theApp->getAskDeleteNewDocs())
147     pImageDoc->Modify (true);
148   pImageDoc->UpdateAllViews (NULL);
149   if (ImageFileView* imageView = pImageDoc->getView()) {
150     imageView->OnUpdate (imageView, NULL);
151     imageView->getFrame()->SetFocus();
152     imageView->getFrame()->Show(true);
153   }
154   *theApp->getLog() << m_pszLabel << "\n";
155   pImageFile->labelAdd (m_pszLabel, getTimerEnd());
156
157   setDone();
158 }
159
160
161 ImageFile*
162 RasterizerSupervisor::getImageFile()
163 {
164   ImageFile* pImageFile = new ImageFile (m_iNX, m_iNY);
165
166   size_t iColSize = sizeof(ImageFileValue) * m_iNY;
167
168   ImageFileArray globalArray = pImageFile->getArray();
169   int iGlobalCol = 0;
170   for (int iw = 0; iw < getNumWorkers(); iw++) {
171     ImageFileArray childArray = m_vecpChildImageFiles[iw]->getArray();
172     for (int iCol = 0; iCol < m_vecpChildImageFiles[iw]->nx(); iCol++) {
173       memcpy (globalArray[iGlobalCol++], childArray[iCol], iColSize);
174     }
175   }
176   return (pImageFile);
177 }
178
179
180 /////////////////////////////////////////////////////////////////////
181 //
182 // Class RasterizerWorker -- A worker thread
183 //
184 /////////////////////////////////////////////////////////////////////
185
186 void
187 RasterizerWorker::SetParameters (PhantomFileView* pPhantomView, ImageFile* pImageFile, int iNX, int iNY, int iNSample, double dViewRatio)
188 {
189   m_pImageFile = pImageFile;
190   m_iNX = iNX;
191   m_iNY = iNY;
192   m_pPhantomView = pPhantomView;
193   m_iNSample = iNSample;
194   m_dViewRatio = dViewRatio;
195 }
196
197 wxThread::ExitCode
198 RasterizerWorker::Entry ()
199 {
200   const Phantom& rPhantom = m_pPhantomView->GetDocument()->getPhantom();
201   wxCommandEvent eventProgress (wxEVT_COMMAND_MENU_SELECTED, BackgroundSupervisor::MSG_WORKER_THREAD_UNIT_TICK);
202   for (int iUnit = 0; iUnit < m_iNumUnits; iUnit++) {
203     if (TestDestroy()) {
204 #ifdef DEBUG
205       if (theApp->getVerboseLogging()) {
206         wxString msg;
207         msg.Printf("Worker thread: Received destroy message at work unit #%d\n", iUnit);  
208         wxCommandEvent event( wxEVT_COMMAND_MENU_SELECTED, MAINMENU_LOG_EVENT );
209         event.SetString( msg );
210         wxPostEvent( theApp->getMainFrame(), event ); 
211       }
212 #endif
213       break;
214     }
215     rPhantom.convertToImagefile (*m_pImageFile, m_iNX, m_dViewRatio, m_iNSample, Trace::TRACE_NONE, 
216       iUnit + m_iStartUnit, 1, iUnit);
217     wxPostEvent (m_pSupervisor, eventProgress);
218   }
219   wxCommandEvent eventDone (wxEVT_COMMAND_MENU_SELECTED, BackgroundSupervisor::MSG_WORKER_THREAD_DONE);
220   eventDone.SetInt (m_iThread); // Send back thread# that has finished
221   wxPostEvent (m_pSupervisor, eventDone);
222
223   while (! TestDestroy())
224     Sleep(100);
225
226   return reinterpret_cast<wxThread::ExitCode>(0);
227 }
228
229 void
230 RasterizerWorker::OnExit ()
231 {
232 }