tag:blogger.com,1999:blog-74542782018-03-06T03:03:25.251-04:00Pinyo's Personal Blogpinyotaehttp://www.blogger.com/profile/08056348551542825367noreply@blogger.comBlogger239125tag:blogger.com,1999:blog-7454278.post-33648718097839279682012-09-28T17:08:00.001-04:002012-09-29T04:58:03.081-04:00Boost 1.48+, BOOST_JOIN, and Qt<p>(September 29, 2012)</p> <p>I am using Visual C++ 2010, Boost Library, and Qt (of course, with some other libraries such as OpenCV, but they are not relevant). This combination can lead to headache if Boost version is 1.48+ (mine is 1.51) and Qt 4.7.3+ (mine is 4.8.3).&#160; The problem prevents us from successful compile and we will get Parse error at &quot;BOOST_JOIN&quot;. The error message I got from Visual C++ 2010 is boost_1_51_0/boost/type_traits/detail/has_binary_operator.hp(50): Parse error at &quot;BOOST_JOIN”.&#160; This problem occurred during Qt’s Moc'ing.</p> <p>A file in Boost that causes this error message can be varied.&#160; Mine was boost/type_traits/detail/has_binary_operator.hp, but other people seemed to encounter a similar error in other files.&#160; The discussion is available at <a href="https://bugreports.qt-project.org/browse/QTBUG-22829">https://bugreports.qt-project.org/browse/QTBUG-22829</a>.&#160; The cause of the issue is Qt’s moc.exe.&#160; </p> <p>Fortunately, we can solve the issue by doing something with moc’s parameters. To be exact, we can solve the issue by sending an option&#160; <br /><strong>-DBOOST_TT_HAS_OPERATOR_HPP_INCLUDED&#160; <br /></strong>to moc. If you install Qt VS Addin, you can right click a project and choose ‘Qt project settings.’ There, you set the MocOptions as shown in a figure below.</p> <p><a href="http://lh6.ggpht.com/-S9qbofrU2sQ/UGYRy4P8ruI/AAAAAAAAANo/7VxOAdfnFMU/s1600-h/image%25255B7%25255D.png"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: block; float: none; border-top-width: 0px; border-bottom-width: 0px; margin-left: auto; border-left-width: 0px; margin-right: auto; padding-top: 0px" title="image" border="0" alt="image" src="http://lh5.ggpht.com/-ewK9X4XWrkc/UGYR0XpJrUI/AAAAAAAAANw/Sr3Oor79hP4/image_thumb%25255B3%25255D.png?imgmax=800" width="417" height="505" /></a></p> pinyotaehttp://www.blogger.com/profile/08056348551542825367noreply@blogger.com0tag:blogger.com,1999:blog-7454278.post-65909637933496571452012-01-02T03:33:00.001-04:002013-05-18T11:21:59.708-04:00Prevent Autorun/Autoplay of USB Drives(Jan 2, 2012)<br />Many old machines in Silpakorn Computer Labs are still using Windows XP and I need to disable Autoplay from USB devices to avoid virus spreading from the devices to these machines.&nbsp; Luckily, the XP is Professional version and it is easy to disable the Autoplay.<br />Details on how to disable the Autorun functionality in Windows are available at <a href="http://support.microsoft.com/kb/967715/en-us">http://support.microsoft.com/kb/967715/en-us</a>.&nbsp; Here, I discuss only Windows XP Professional (Home edition is harder to deal with regarding this matter). &nbsp;For Windows 7, you can see&nbsp;<a href="http://www.youtube.com/watch?v=U6ubWhGVF2U">this video</a>&nbsp;to learn how to disable USB Autoplay. The method for Windows XP Professional is described below:<br /><ol><li>Click the start button and click ‘Run …’</li><li>Insert command ‘Gpedit.msc’ and enter.</li><li>Under <strong>Computer Configuration</strong>, expand <strong>Administrative Templates</strong>, expand <strong>Windows Components</strong>, and then click <strong>Autoplay Policies</strong>.</li><li>In the <strong>Details</strong> pane, double-click <strong>Turn off Autoplay</strong>.</li><li>Click <strong>Enabled</strong>, and <span style="color: red;">then select <strong>All drives</strong></span> in the <strong>Turn off Autoplay</strong> box to disable Autorun on all drives.</li><li>Restart the computer.</li></ol><strong>Side notes</strong>: many people think that autorun and autoplay are the same thing.&nbsp; The idea is right in one sense and wrong in another.&nbsp; As far as I know, Autorun is some thing for running the CD/DVD contents automatically.&nbsp; Autoplay, however, seem to be broader and is applicable to any USB devices.&nbsp; So, the behaviors of Autorun and Autoplay are practically the same, but Microsoft gave them different names.pinyotaehttp://www.blogger.com/profile/08056348551542825367noreply@blogger.com1tag:blogger.com,1999:blog-7454278.post-81776205043764732892011-12-29T10:14:00.001-04:002011-12-29T10:32:10.160-04:00OpenOffice.org / LibreOffice: Make Table of Contents hyperlink/clickable<p>(Dec 29, 2011)</p> <p>Today, I tried to make the table of contents in LibreOffice hyperlink/clickable.&#160; The solution is available in the <a href="http://user.services.openoffice.org/en/forum/viewtopic.php?f=7&amp;t=4466">forum</a>.&#160; I, however, want to show a pictorial procedure here.&#160; The step was taken from LibreOffice 3.4.4, but should be very similar to what is for OpenOffice.</p> <ol> <li>Go to menu Insert –&gt; Indexes and Tables –&gt; Indexes and Table. <br /> <br /><a href="http://lh5.ggpht.com/-nvs2kIIdrK4/Tvx1s8eFWFI/AAAAAAAAAL0/h3pqu5I59BI/s1600-h/libreoffice1_edit%25255B4%25255D.png"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="libreoffice1_edit" border="0" alt="libreoffice1_edit" src="http://lh4.ggpht.com/-dSUnU9TVklU/Tvx1twlcFQI/AAAAAAAAAL8/DHpNcYbfCTo/libreoffice1_edit_thumb%25255B2%25255D.png?imgmax=800" width="438" height="498" /></a> <br /><strong>Figure 1 Menu for inserting the table of contents</strong>. <br /> <br /></li> <li>In the setting window for a table of contents, highlight the Entries tab.&#160; Then, you see the ‘Structure’ of the table of content.&#160; Click on the white space before the Entry code [E].&#160; Then, click on the Hyperlink button to insert a link-start code [LS]. <br /> <br /><a href="http://lh3.ggpht.com/-RHug9Lm6Myw/Tvx1uzTvIEI/AAAAAAAAAME/uaeDTduhP7Y/s1600-h/libreoffice2%25255B5%25255D.png"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="libreoffice2" border="0" alt="libreoffice2" src="http://lh3.ggpht.com/-9zFIIobmW-U/Tvx1v-AHiLI/AAAAAAAAAMM/AKQXuDn7M_w/libreoffice2_thumb%25255B3%25255D.png?imgmax=800" width="775" height="396" /></a> <br /><strong>Figure 2 How to initialize the hyperlink structure of a hyperlink entry</strong>. <br /> <br /></li> <li>We must end the hyperlink.&#160; The position to end the hyperlink depends on us.&#160; We can make only the text hyperlink, and if you wish, you can make the entire line of each entry hyperlink.&#160; If you want only the text to be a hyperlink, click on the space after the Entry code [E], then click the Hyperlink button again to insert the link-end code [LE] and press OK.&#160; The result is shown in Figure 3. <br /> <br /><a href="http://lh3.ggpht.com/-zgKrry8bcqA/Tvx1w_0_I5I/AAAAAAAAAMU/twbfl7QfWF0/s1600-h/libreoffice3%25255B3%25255D.png"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="libreoffice3" border="0" alt="libreoffice3" src="http://lh3.ggpht.com/-lmZBFl0DWQs/Tvx1yB42qmI/AAAAAAAAAMc/M-K95kk19VE/libreoffice3_thumb%25255B1%25255D.png?imgmax=800" width="782" height="438" /></a> <br /><strong>Figure 4 Result from surrounding only the entry code [E] by the link-start and link-end codes.</strong> <br /> <br />If you want the entire entry, including the page number, to be clickable, you need to insert a link-end code after the page-number code [#].&#160; Unfortunately, due to an issue of the LibreOffice, you can’t click on the space after [#] once you insert an [LS] code.&#160; You have to circumvent the problem by click on the space before [#] and use an arrow key of the keyboard to move the cursor behind [#].&#160; The result is shown in Figure 5. <br /> <br /><a href="http://lh3.ggpht.com/-_yOC5IvFvqw/Tvx1zDCye9I/AAAAAAAAAMk/yNcuaWbrMR8/s1600-h/libreoffice4%25255B4%25255D.png"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="libreoffice4" border="0" alt="libreoffice4" src="http://lh3.ggpht.com/-QFAK0uMrhdQ/Tvx10ByS7xI/AAAAAAAAAMs/JI8f3JmitF0/libreoffice4_thumb%25255B2%25255D.png?imgmax=800" width="781" height="438" /></a> <br /><strong>Figure 5 Result from surrounding the entry code [E] to the page-number code [#] by the link-start and link-end codes.</strong> <br /> <br /></li> <li>As for the final step, you might want to make other entry levels hyperlink, as well.&#160; You can repeat the process by highlighting other level you want to change. </li> </ol> <p>Hope this helps, <br />Pinyo</p> <p>Note: this post is written in Windows Live Writer.&#160; This is the first time I try uploading from the blog writer.&#160; I hope every thing will be fine.&#160; I did not post any thing for a long time once Google Docs cannot directly push my documents to blogger anymore after it upgraded its text editor. <br /> <br />As usual, feel free to post comments and questions.&#160; Don’t worry if this post looks old in the future.&#160; I receive your feedback via email no matter how old the post is.</p> <p>[Update: Wow, Windows Live Writer works so well.&#160; I can continue my blogging life once more.] </p> pinyotaehttp://www.blogger.com/profile/08056348551542825367noreply@blogger.com10tag:blogger.com,1999:blog-7454278.post-14647848522337959892011-02-19T03:33:00.002-04:002011-02-19T03:46:21.552-04:00Create User-Defined Environment Variables (Macros) in Visual StudioDue to difficulty on the Google Docs side, I cannot easily publish my note from it here (at least in the good old way). So, please follow <a href="https://docs.google.com/document/pub?id=13ZuzQMVth64Ak2_K6UITf6NvmtGETJZQObbaTsHwhAs">this link to read my note</a> in a full screen mode. If you have any comments or suggestions, please let me know.<br /><br />Note: there is a discussion about this difficulty in <a href="http://www.google.com/support/forum/p/Google%20Docs/thread?tid=4207ea9031f77c84&amp;hl=en">this link</a>. I resort to an iframe tag, but it is not as good as I want. Please see below. I think I will have to do this for a while.<br /><br /><iframe src="https://docs.google.com/document/pub?id=13ZuzQMVth64Ak2_K6UITf6NvmtGETJZQObbaTsHwhAs&amp;embedded=true" width=800 height=400></iframe>pinyotaehttp://www.blogger.com/profile/08056348551542825367noreply@blogger.com2tag:blogger.com,1999:blog-7454278.post-66967337756233456082010-11-27T22:26:00.002-04:002011-01-03T21:16:31.900-04:00TracExplorer and VS 2010 Integration<h1>TracExplorer and VS 2010 Integration</h1>(Nov 27, 2010)<br><h2>Introduction</h2>Caveat: I&#39;m new to an issue tracker system.&nbsp; How I use Trac and TracExplorer, as described here, may not be a good practice, but it worked.<br>(you can skip the introduction if you already know Trac and TracExplorer well)<br><br>Trac is an interesting issue tracking system.&nbsp; Its default feature set provides what many software developers need.&nbsp; Trac&#39;s plugin architecture also allows us to add more features to the system if we need them.&nbsp; Therefore, default Trac is useful and relatively simple.&nbsp; Extended Trac is more powerful, but may be complicated.&nbsp; Using Trac inside the Visual Studio can also be convenient, provided that the integration provides adequate features and user interfaces.<br><br>TracExplorer has a fascinating idea for VS 2005 and 2008 integration.&nbsp; However, the available binary in source forge does not work with VS 2010.&nbsp; In addition, TracExplorer (as of version 0.20 beta) is not feature rich.&nbsp; It is rather inadequate and not improved for months.&nbsp; For example, TracExplorer does not allow the user to create a new ticket.&nbsp; A typical web-based user interface is needed.&nbsp; Yet, it allows us to quickly view and modify tickets.&nbsp; Many people may be satisfied with the available features.<br><br>This integration contains two parts: installatiion of Trac&#39;s XML-RPC plugin, which is a requirement of TracExplorer, and VS 2010 integration.<br><br><h2>Installation of XML-RPC plugin</h2><ol><li>Get the <a href="http://trac-hacks.org/wiki/XmlRpcPlugin" title="plugin">plugin</a> by downloading its <a href="http://trac-hacks.org/changeset/latest/xmlrpcplugin?old_path=/&amp;filename=xmlrpcplugin&amp;format=zip" title="source package">source package</a>.&nbsp; Don&#39;t worry that you do not get the binary. The actual installation is simple.<br><br></li><li>Extract the source package to a preferred folder.&nbsp; Inside the package, we mainly use the source inside the trunk.&nbsp; Other folders usually contain outdated version provided for compatibility.<br><br></li><li>Generate an &#39;egg&#39; package. This step requires Python, but we should already have it installed as Trac&#39;s prerequisite.&nbsp; A default Python&#39;s folder from BitNami is &quot;C:\Program Files\BitNami Trac Stack\python\python.&quot; <br>Therefore, in the command prompt of the trunk folder, type <br><br>&quot;C:\Program Files\BitNami Trac Stack\python\python&quot; setup.py bdist_egg&nbsp; [Note: the double qoutes are needed to dealing with a path with space.]<br><br></li><li>The necessary outputs is in the newly created &#39;dist&#39; folder.&nbsp; Copy all *.egg files (typically, there is only one egg file for this plugin) from there to Trac&#39;s plugin folder.&nbsp; An example of the plugin folder is <br>&quot;C:\Users\username\BitNami Trac Stack projects\InitialProject\plugins&quot;<br><br></li><li>change trac.ini of a project that wants to use the plugin by including lines<br>[components] <br>tracrpc.* = enabled <br><br>Note that if the [components] section already exists, there is no need to create a new one.&nbsp; Just append &#39;tracrpc.* = enabled&#39; to the section.<br><br></li><li>Restart the apache service.&nbsp; It is important to note that the service name is tracApache if you use BitNami.&nbsp; If you need to run this service from a command line, use<br>&quot;C:\Program Files\BitNami Trac Stack\apache2\bin\httpd.exe&quot; -k runservice</li></ol><br>If you want to install this plugin for every project, try using easy_install descriped in <a href="http://trac-hacks.org/wiki/XmlRpcPlugin" id="m2tz" title="Trac website">Trac website</a>.<br><br><h2>Visual Studio 2010 Integration</h2>This section is probably why you come to this page.&nbsp; You may think that you need an installer for integration, but it is not necessary at all.&nbsp; All you need are compatible add-in binaries and add-in description file.<br><br><ol><li>Download the package I built from <a href="http://docs.google.com/leaf?id=0B-WlB8Fgc324MDJhNWRhZGQtMjgzNy00Mzk3LThmYzYtYzQ5ODNhOWU1ODZk&amp;hl=en" id="ra0y" title="this link">this link</a>.&nbsp; This package includes binaries and description file.&nbsp; If you are interested in how I prepared the package, see the next section.&nbsp; <br><br></li><li>Unpack it to your preferred folder.&nbsp; No need to bother with &quot;Program Files&quot;.&nbsp; Any folder will do.<br><br></li><li>Open VS 2010.<br><br></li><li>Go to &#39;Tools-&gt;Options.&#39;<br><br></li><li>In the &#39;Add-in/Macros Security&#39; in the &#39;Environment&#39; node.&nbsp; Then, &#39;Add..&#39; the path to the folder in you chose in Step 2.<br><br></li><li>Close and reopen VS 2010.<br><br></li><li>Verify add-in installation: (1) Go to &#39;Tools-&gt;Add-inManager&#39;.&nbsp; You should see TracExplorer.VSTrac listed there; (2) By clicking &#39;View&#39; in the menu bar, you should see &#39;Trac Explorer.&#39;<br></li></ol><br><h2>Preparation of Binary Package</h2><p>This part is for those who are curious about how I built the add-in from the source code provided in SourceForge.net.<br></p><p>Note: I do not modify any source code.&nbsp; I just rebuild the binary and add a proper add-in description file.<br></p><br><ol><li>Install TortoiseSVN in its default folder.&nbsp; You need TortoiseSVN, as the build script uses a file from TortoiseSVN.&nbsp; The file is specified by the default path of TortoiseSVN. If you already installed it elsewhere, see note at the end of this section.<br><br></li><li>Check out the source tree from SourceForge.&nbsp; The SVN command is &#39;<font face="Courier New">svn co https://vstrac.svn.sourceforge.net/svnroot/vstrac vstrac.&#39;</font>&nbsp; If you use TortoiseSVN to do this, just enter the URL <font face="Courier New">https://vstrac.svn.sourceforge.net/svnroot/vstrac</font>.<br><br>Do not use GNU tarball, as the build script needs to obtain some information of the SVN source tree.&nbsp; This information is automatically available if you use SVN to check out the source tree.<br><br></li><li>Go to the &#39;trunk/src&#39; folder.&nbsp; Use VS 2010 to open TracExplorer2008.sln.<br><br></li><li>Rebuild the solution in a release mode.&nbsp; Whatever you try to do, you will get x86 binaries compatible with VS 2010 in the &#39;trunk/bin&#39; folder.<br><br></li></ol><b>Note</b>: What if I installed TortoiseSVN in a non-default foder?<br>In this case, version_scm.bat in the &#39;build&#39; folder will not work.&nbsp; You, however, can specify your TortoiseSVN path by modifying the batch file.<br><br><b>Trivia</b>: In SourceForge, this software is called TracExplorer, but in Visual Studio&#39;s view, it becomes Trac Explorer (with space added).<br><br>Hope this helps,<br>Pinyo<br>pinyotaehttp://www.blogger.com/profile/08056348551542825367noreply@blogger.com2tag:blogger.com,1999:blog-7454278.post-64660276909635654922010-11-12T21:50:00.002-04:002011-02-18T02:34:29.691-04:00Building 64-bit Qt 4.7 using MinGW-w64<h1>Building 64-bit Qt 4.7 using MinGW-w64</h1>(Nov 12, 2010)<br><br>I successfully built 64-bit Qt libraries using MinGW-w64.&nbsp; Although I had to change Qt source code, it was only one line of code in the current source tree of qt-mingw-w64.&nbsp; The steps I took to built 64-bit Qt are described below.&nbsp; Note that my explanation is a bit verbose, as those who just start using MinGW or Qt may need additional information. <br><br><ol><li>Obtain Qt 4.7 source code.</li><ul><li>Go to http://gitorious.org/+qt-mingw-w64/qt/qt-mingw-w64-qt</li><li>Click on the &#39;Source tree&#39; button.&nbsp; Note that you can directly go to <a href="http://qt.gitorious.org/+qt-mingw-w64/qt/qt-mingw-w64-qt/trees/master" id="gpa-" title="this link">this link</a>.&nbsp; However, go to the link above allows you to read recent activities of Qt development that may related to you.</li><li>On the right side, you see several &#39;branches&#39;.&nbsp; As of Nov 12, 2010, the one you want to use is plain &#39;4.7,&#39; which already merges Webkit facility.</li><li>Once you click on the &#39;4.7&#39; button, you probably need to wait a minute or two.&nbsp; This allows the server to create tar.gz for downloading.&nbsp; Basically, the package is prepared on the fly.&nbsp; This is how gitorious works.<br><br></li></ul><li>Unpack the source tree to your preferred folder.&nbsp; For this note, I unpacked it to &#39;F:\Qt\qt-4.7.1_mingw_w64.&#39;&nbsp; This path is used here for a demonstration purpose.<br><br></li><li>Fix file &#39;src\corelib\tools\qsimd.cpp&#39; by changing line 289 from &#39;long tmp&#39; to &#39;quint64 tmp,&#39; as suggested by Jonathan Liu [<a href="http://qt.gitorious.org/qt/qt/commit/4c0e59e6ad6b697a28f7c57540fb2eb0042d04d0?diffmode=sidebyside" id="aq5-" title="ref">ref</a>].&nbsp; See the ref for more information if you don&#39;t understand what I meant.&nbsp; Please note that if you get a newer Qt version, this problem may already be solved.<br><br></li><li>Get MinGW-w64 from sourceforge.&nbsp; I use the native compiler for Windows 64-bit.&nbsp; FYI: MinGW offers a cross-compilation feature.&nbsp; You can use Linux or 32-bit Windows to produce 64-bit Windows binary.</li><ul><li>Go to http://sourceforge.net/projects/mingw-w64/files/</li><li>Click on Section &#39;Toolchains targetting Win64&#39;</li></ul><ul><li>Pick the release you like.&nbsp; I suggest you use personal build from sezero, as sezero usually adds some patches or features that you might want to use (e.g., updated OpenGL and OpenCL headers).&nbsp; I employed <a href="http://sourceforge.net/projects/mingw-w64/files/Toolchains%20targetting%20Win64/Personal%20Builds/sezero_20101003/mingw-w64-bin_x86_64-mingw_20101003_sezero.zip/download" id="zuea" title="mingw-w64-bin_x86_64-ming_20101003_sezero.zip">mingw-w64-bin_x86_64-ming_20101003_sezero.zip</a>.&nbsp; By the time you get MinGW from sourceforge, the build may be gone.&nbsp; Yet, you are supposed to get a newer version than mine.</li><li>If you wonder what are inside each sezero build see his note in Section &#39;Toolchains targetting Win64 -&gt; Personal Builds -&gt; sezero_20101003.&#39;&nbsp; sezero did a good job in bookkeeping (at least it seemed).<br><br></li><li>Personal build of rubenvb is probably an interesting choice, as he appears to be a Qt contributor.&nbsp; I believe that his MinGW build should not have a serious issue with Qt compilation.<br><br></li></ul><li>Unpack MinGW to a preferred place.&nbsp; For this note, it is &#39;D:\mingw_w64_sezero_oct_3_2010.&#39;<br><br></li><li>Go to D:\mingw_w64_sezero_oct_3_2010\bin and change gmake.exe to mingw32-make.exe.&nbsp; Note that it is MinGW&#39;s <b>g</b>make not Qt&#39;s <b>q</b>make.&nbsp; I backed up original mingw32-make.exe to other file first, although they might be exactly the same binary in the sezero&#39;s build.<br><br></li><li>Download Perl.&nbsp; Yes, you need Perl to syncqt during compilation.&nbsp; I suggest <a href="http://www.activestate.com/activeperl/downloads" id="xks3" title="ActivePerl Community Edition">ActivePerl Community Edition</a>.&nbsp; If you want to repeat what I did here, download Windows 64-bit version with an MSI installer.&nbsp; I did not like Strawberry Perl, as I encountered many issues with it during past summer, especially the fact that it comes with its own GCC.&nbsp; Its GCC confused me about GCC version since both Strawberry&#39;s and MinGW&#39;s GCC showed up in the path.&nbsp; These issues may be already resolved by now, though.<br><br></li><li>Install Perl.&nbsp; What a simple task if you have admin right to your machine.&nbsp; If you don&#39;t, see steps below.&nbsp; <br></li><ul><li>Download AS Package (ZIP).<br></li></ul><ul><li>Unpack and set path to &#39;base_perl_path/bin&#39; and &#39;base_perl_path/site/bin.&#39;</li><li>If you want a temporary session path for your command prompt (cmd.exe), type &#39;set PATH=C:\Perl64\bin;C:\Perl64\site\bin;%PATH%, provided that you unpack its main contents to C:\Perl64 and discard its &#39;support&#39; folder.&nbsp; Don&#39;t close this command prompt yet because your path settings are temporary.&nbsp; You need to use it until the end.<br><br></li></ul><li>Now, you have all you need to embark the actual compilation phase. Set path to your MinGW folder.&nbsp; For example, &#39;set PATH=D:\mingw_w64_sezero_oct_3_2010\bin;%PATH%.&#39;<br>If you want to know what your current path is, type &#39;echo %PATH%.&#39;<br><br></li><li>Set QTDIR variable by typing &#39;set QTDIR=F:\Qt\qt-4.7.1_mingw_w64\bin.&#39;<br><br></li><li>Go to Qt base folder (F:\Qt\qt-4.7.1_mingw_w64) and run configure from the command prompt.&nbsp; You can choose any configure options, perhaps except phonon (my Qt build did not have phonon).&nbsp; I used &#39;plain&#39; configure that generated everything, but you might want to get rid of many things, especially qt3 support, examples, and demos.<br><br><i>Update (Feb 18, 2011)</i>: it is easy to build Qt with phonon.&nbsp; The option, however, is off by default for MinGW.&nbsp; I tested with <br><font face="courier new">configure -opensource -phonon -no-qt3support -nomake example -nomake demos<br><font face="verdana">Although I did not test if the created libraries work or not, things are built smoothly.</font></font><br><br></li><li>Type &#39;gmake.&#39;&nbsp; Note that if you want to try multi-threaded compilation, type &#39;gmake -jx,&#39; where x is the number of threads.&nbsp; For instance, &#39;gmake -j2&#39; for a dual-core machine, &#39;gmake -j4&#39; for a quad-core machine, and &#39;gmake -j6&#39; for a six-core machine (if you want to put every core to work).&nbsp; I, however, just used gmake with no option since I wanted to simplify everything for this build.<br><br></li><li>Wait with patience.</li></ol><br>The following summarizes downloads and tweaks I made during the above steps.&nbsp; Basically, we need to do only two things in addition to what most people do with mingw 32-bit.&nbsp; I have not try building phonon yet (and I think I don&#39;t need it for a long time).<br><h3>Download summary</h3><ol><li>Qt 4.7 mingw-w64 branch (~ 130 MB).&nbsp; See step 1.<br></li><li>MinGW-w64 (~ 55 MB).&nbsp; See step 4.<br></li><li>ActivePerl (~ 24 MB).&nbsp; See step 7.<br></li></ol><h3>Tweak summary</h3><ol><li>Change source code (1 file, 1 line).&nbsp; See step 3.</li><li>Change gmake to mingw32-make.exe.&nbsp; See step 6.&nbsp; (May not be necessary any more.)<br></li></ol><br><br>Hope this helps,<br>Pinyo Taeprasartsit<br><br>Additional reference: <a href="http://www.mail-archive.com/mingw-w64-public@lists.sourceforge.net/msg00952.html" id="z9jf" title="mingw-w64 mail archive">mingw-w64 mail archive</a><br><br><br>I welcome questions and comments.&nbsp; Feel free to ask and share if you have any.<br><br>pinyotaehttp://www.blogger.com/profile/08056348551542825367noreply@blogger.com14tag:blogger.com,1999:blog-7454278.post-52175645616821723292010-08-06T21:21:00.002-04:002011-12-14T13:10:36.628-04:00VTK Installation on Windows 64-bit for Visual Studio<h1>VTK Installation on Windows 64-bit for Development in Visual Studio</h1>VTK installation in Windows 32-bit is typically painless, as the platform was already tested by many developers and became mature.&nbsp; (Yet, if you have a problem with it, the troubleshooting note at the end of this page might help.)&nbsp; For Windows and VTK 64-bit, however, we may encounter a few issues.&nbsp; This note describes what I did to install VTK 5.6 on my MS Windows 7 Home Premium 64-bit.&nbsp; This note should be applicable to those who need to do the same thing.<br><br>The first part is for installation with default VTK build options.&nbsp; These options are VTK_USE_CHARTS, VTK_USE_GEOVIS, VTK_USE_INFOVIS, VTK_USE_N_WAY_ARRAYS, VTK_USE_RENDERING, and VTK_USE_VIEWS.<br><ol><li>Download VTK 5.6 source from http://vtk.org/VTK/resources/software.html.</li><li>Extract it to create a source folder.<br></li><li>Open CMake (I used 2.8.1, and it is supposed to work with the most recent version at cmake.org).</li><li>In CMake, choose a source and binary folders (Figure 1).<br><br><div id="q26x" style="text-align:left"><img src="http://docs.google.com/File?id=dggq8h5d_520hmzcmbg2_b" style="height:507.009px;width:648px"></div><br><b>Figure 1</b>.&nbsp; CMake 2.8.1 after source code and binary folder selected.<br><br></li><li>Click the &#39;Configure&#39; button.</li><li>CMake asks about generator (compiler) we want to use (Figure 2).&nbsp; The one we want to use is Visual Studio 9 2008 Win64 (the one without suffix Win64 is 32-bit) with &#39;Use default native compiler&#39;.&nbsp; We can also use Visual Studio 10 Win64 if a target development platform is Visual Studio 10.&nbsp; Using MinGW will generate incompatible binary for Visual Studio development.&nbsp; In addition, 64-bit MinGW is quite tricky to use as of Aug 2010.<br><br><div id="xkw4" style="text-align:left"><img src="http://docs.google.com/File?id=dggq8h5d_521fn4vn2zj_b" style="height:390px;width:500px"></div><div style="text-align:-webkit-auto"><br></div><b>Figure 2</b>. &#39;Choose compiler&#39; dialog<br><br></li><li>If initial configuration goes fine, there will be no critical errors and VTK build options will be available for us to choose (Figure 3).<br><div id="vujl" style="text-align:left"><img src="http://docs.google.com/File?id=dggq8h5d_522dr8bdj75_b" style="height:634.6px;width:648px"></div><div style="text-align:-webkit-auto"><br></div><b>Figure 3</b>.&nbsp; Build options for VTK after the initial configuration.&nbsp; Red regions in CMake highlight new options since the previous configuration.&nbsp; As this is the first time, every option is new and highlighted.<br><br></li><li>I used the default options.&nbsp; This option builds a static libraries, which is what I prefer.<br></li><li>I think options VTK_USE_PARALLEL may help speed up processing in a multi-core system, but I need to learn more about it.&nbsp; Also, VTK_USE_QT is probably good for me, as I have used Qt a lot recently.&nbsp; Yet, I need to know what it does first.</li><li>Click the &#39;Configure&#39; button again when options are settled.</li><li>Click the &#39;Generate&#39; button to generate a proper visual studio solution tree.</li><li>Go to the output folder specified earlier, you should see &#39;VTK.sln&#39;.</li><li>Open the solution and &#39;Build Solution&#39;.&nbsp; It will take a while to finish (around 5-10 minutes).&nbsp; Note that if you only want to use VTK and do not intend to debug into its source code, <b>it is recommend to build it in the release mode</b>.<br></li><li>In the solution tree, right click on the &#39;INSTALL&#39; project and &#39;Build&#39;. &nbsp;Update Dec 15, 2011: some systems may experience a build error due to write permission to C:\Program Files (x86). &nbsp;This depends on your Windows settings. &nbsp;One way to solve this issue is to close Visual Studio and run it &#39;as administrator&#39; (credit to Alex Southern, see his comment below).</li><li>The outputs are kept in C:\Program Files (x86)\VTK.&nbsp; Both include and lib folders are what we are going to use in further software development.<br></li><li>If you want to build both 32- and 64-bit packages, move the outputs to another folder and repeat the process.&nbsp; Only the generater in step 6 is needed to change.&nbsp; We have to move the current outputs because new outputs will be saved to the same folder.<br><br></li></ol><h3><a id="TOC-Build-VTK-with-parallel-processing-" name="TOC-Build-VTK-with-parallel-processing-"></a>Build VTK with parallel-processing and Qt-support options</h3>Next, I will discuss installation of VTK with additional options for Visual Studio 2008.&nbsp; These options are VTK_USE_QT and VTK_USE_PARALLEL.&nbsp; We can jump to step 7 discussed in the last section. At this point, we only need to check the QT and PARALLEL options and then, hit the &#39;Configure&#39; button the project again.&nbsp; CMake will configure the project and comes up with two new options highlighted in red (Figure 4).&nbsp; Once you set QT_QMAKE_EXECUTABLE to your target version, hit the &#39;Configure&#39; button for the third time.&nbsp; If every thing goes fine, you will get a refreshed dialog with message &quot;Configuring done&quot;, as depicted in Figure 5.&nbsp; There are chances that you did not succeed or get a wrong Qt version.&nbsp; If the latter is your problem, read the caption of Figure 4.&nbsp; If it fails for other reason, please see the troubleshooting note at the end of this document.&nbsp; I hope it has what you need.<br><br>The rest of the process is generally the same.&nbsp; If you encounter linking errors when you build VTK in Visual Studio, see Topic 2 in the troubleshooting note provided below.<br><br><div id="abi2" style="text-align:left"><img src="http://docs.google.com/File?id=dggq8h5d_523g9tjmphk_b" style="height:634.6px;width:648px"></div><div style="text-align:-webkit-auto"><br></div><b>Figure 4</b>.&nbsp; CMake after the second configuration with QT and PARALLEL.&nbsp; QT_QMAKE_EXECUTABLE is selected by what you do with Qt integration for Visual Studio.&nbsp; In other words, CMake checks the path of default Qt version you set in Visual Studio and use it here.&nbsp; In fact, <b>CMake and VTK build script strictly use the default Qt version</b>.&nbsp; You cannot effectively change Qt version here, as it will be eventually reset to the VS default version. Therefore, you may need to open VS and change Qt default version to set QT_QMAKE_EXECUTABLE.<br><br><div id="nttr" style="text-align:left"><img src="http://docs.google.com/File?id=dggq8h5d_524cxq7qdcm_b" style="height:664.272px;width:648px"></div><div style="text-align:-webkit-auto"><br></div><b>Figure 5</b>. A successful configure dialog.<br><br><h3><a id="TOC-Troubleshooting-Note-for-Qt-Option" name="TOC-Troubleshooting-Note-for-Qt-Option"></a>Troubleshooting Note for Qt Option</h3>1. <b>Problem</b>: &quot;I specified qmake path correctly, but it seems that CMake looks for qmake in a wrong path.&quot;<br><br><b>Solution</b>:<br>You may set QT_QMAKE_EXECUTABLE to point to qmake correctly, but this problem may arise since CMAKE will use outdated qmake properties, such as QT_INSTALL_PREFIX and QT_INSTALL_BINS.&nbsp; For example, you build Qt in one path and later on you move it to another.&nbsp; The properties, however, is fixed at the time you build Qt.&nbsp; You can confirm this issue by going to qmake&#39;s make folder and using the command prompt to type &#39;qmake -query&#39; to see all qmake properties.<br><br>If the issue is confirmed, you need to compile qmake again (<i>not the whole Qt library set</i>).&nbsp; Alternatively, you can just move or copy your Qt directory to the old place to resolve the issue.&nbsp; If moving or copying Qt folder is not an option, you can quickly re-compile qmake by<br><ul><li>Rename the bin and qmake folders of Qt to something else.</li><li>Copy the pristine bin and qmake folders from the Qt source to the Qt folder.</li><li>Configure Qt from Visual Studio command prompt.&nbsp; For example, by using &#39;configure -platform win32-msvc2008 -release <font face="Courier New">-static -opensource</font><font face="Courier New"> -nomake demo</font> <font face="Courier New">-nomake examples <font face="Courier New">-no-qt3support</font></font> -fast&#39;.&nbsp; You probably did this before when you compiled Qt libraries.</li><li>Copy things from the old bin and qmake folders to your current bin and qmake folders, but make sure you do not replace the new qmake you just compiled.</li><li>Now, you have qmake with updated qmake properties.&nbsp; I hope you can configure VTK in CMake as usual from this point.<br><br><br></li></ul>2. <b>Problem</b>: &quot;I got linking errors when I build VTK in Visual Studio.&nbsp; It complained about PlaySoundW, WSAAsyncSelect, and many more.&quot;<br><br><b>Solution</b>:<br>Based on my experience, this problem is platform specific.&nbsp; You may encounter this issue if you use static library version of Qt and the problems in 32-bit and 64-bit platforms are not the same.&nbsp; These linking problems, however, are related to Windows libraries and occurs when your VTK build script does not correctly include them.<br><br>Fortunately, you can include corresponding libraries yourself with ease by following the guidelines described below.<br><ul><li>Identify problematic projects.&nbsp; Potential problematic projects are QVTKWidgetPlugin, QVTK, QtChartCxxTests, ChartCxxTests, and QVTKCxxTests.</li><li>Search the Internet (or use your prior knowledge, or your MSDN documents) to identify corresponding libraries.&nbsp; For example, the corresponding library of PlaySoundW is Winmm.lib and that of WSAAsyncSelect is Ws2_32.lib.</li><li>Add the libraries to the Visual Studio project properties, as you do normally.&nbsp; Basically, you can right click the project in the Solution Explorer of Visual Studio and select &#39;Properties&#39;.&nbsp; Then, go to node &#39;Configuration Properties -&gt; Linker -&gt; Input&#39; and insert the library name to &#39;Additional Dependencies&#39;.</li></ul><br><br>3. <b>Problem</b>: I checked &#39;VTK_WRAP_PYTHON&#39; and CMake errors occurred.&nbsp; It complaint about PYTHON_INCLUDE_DIR AND PYTHON_LIBRARY.<br><br>The error message looked like:<br><font color="#ff0000">CMake Error: The following variables are used in this project, but they are set to NOTFOUND.</font><p style="margin:0px"><font color="#ff0000">Please set them or make sure they are set and tested correctly in the CMake files:</font></p><p style="margin:0px"><font color="#ff0000">PYTHON_INCLUDE_DIR</font></p><font color="#ff0000">PYTHON_LIBRARY</font><br><br><b>Solution</b>:<br>The two CMake variables seem to come and go and not consistent over VTK versions.&nbsp; You might want to add them yourself to CMakeLists.txt.<br>First, locate IF(VTK_WRAP_PYTHON).&nbsp; Then, modify the section to something like<br><br>IF(VTK_WRAP_PYTHON)<br>&nbsp; SET(VTK_LANGUAGES ${VTK_LANGUAGES} PYTHON)<br>&nbsp; #Addition by Pinyo<br>&nbsp; SET(PYTHON_INCLUDE_DIR &quot;C:/Python31/include&quot;)<br>&nbsp; SET(PYTHON_LIBRARY &quot;C:/Python31/libs/python31.lib&quot;)<br>ENDIF(VTK_WRAP_PYTHON)<br><br>Please note that PYTHON_LIBRARY is the actual library file, not just a folder (although you sometimes see the term python librar<b>ies</b> and think that it is a lot of libraries, not a single file.).<br>Finally, configure and generate make files as usual.<br><br><br>4. <b>Problem</b>: I used VS 2010 64-bit and CMake 2.8.3 and got Q4VTKWidgetPlugin.h(57): error : Undefined interface.&nbsp; This corresponds to line <font face="Courier New"><font color="#010001">Q_INTERFACES</font>(<font color="#010001">QDesignerCustomWidgetCollectionInterface</font>)<font face="verdana">.<br><b><br>Solution</b>:<br></font></font>This is, in fact, a CMake problem.&nbsp; To be exact, the <a href="http://vtk.1045678.n5.nabble.com/Problems-with-compiling-vtk-on-Mac-with-Qt-support-td1237207.html" id="lg0w" title="QT_QTDESIGNER_INCLUDE_DIR is not set correctly">QT_QTDESIGNER_INCLUDE_DIR is not set correctly</a>.&nbsp; An example of the value is <font face="Courier New">include/QtDesigner/</font>.&nbsp; This option is available if we want to generate MinGW Makefiles.&nbsp; This option also was automatically set in the past and it was correct.&nbsp; For an unknown reason, it does not work on some machines (VTK 5.6.1 as of Feb 18, 2011).<br><br>To solve the problem, go to folder GUISupport\Qt and open CMakeLists.txt.&nbsp; Then, add a line<br>SET (QT_QTDESIGNER_INCLUDE_DIR &quot;G:/Workspace/Qt/qt-release-4.7.1-vs2010/include/QtDesigner&quot;)<br>Make sure you adjust the ad hoc path to what suits your computer.<br><br>The above line should be added right after FIND_PATH(QT_QTDESIGNER_INCLUDE_DIR QDesignerComponents ...), as the function FIND_PATH may not work correctly in your build.<br><br>Hope this helps,<br>Pinyo Taeprasartsit<br>(Aug 2010, Feb 2011)<br><br><br>pinyotaehttp://www.blogger.com/profile/08056348551542825367noreply@blogger.com10tag:blogger.com,1999:blog-7454278.post-86353861095380335102010-06-12T15:23:00.002-04:002010-11-27T22:33:25.025-04:00GL_TEXTURE_2D<h1>GL_TEXTURE_2D</h1>In this part, we continue with a convenient and powerful method for 2D OpenGL, 2D texture.<br>The strength of using OpenGL 2D texture over glDrawPixels is that linear filtering can be selected.<br>Moreover, the task is systematic and not tedious. <br><br>I, however, do not know if using RGBA is better in terms of performance or not, but I used it in this example.<br>Thus, we have to modify a way to create a texture image.&nbsp; The A element can be set to 255, as shown below.<br><font size="2"><br></font><font size="2"><font face="courier new">texImage[nColorBytes*(h*m_nWidth + w) + 3] = (GLubyte) 255;</font></font><br><br>To initialize 2D texture with linear filtering, the following code can be used to make a texImage an OpenGL texture.<br><font size="1"><br><font face="courier new"><font size="2">void GLTexture2D::initializeGL()</font></font><font size="2"><br style="font-family:Courier New"><font face="courier new">{</font><br style="font-family:Courier New"><font face="courier new">&nbsp;&nbsp; &nbsp;// Basic initialization</font><br style="font-family:Courier New"><font face="courier new">&nbsp;&nbsp; &nbsp;glClearColor(0.0, 0.0, 0.0, 0.0);</font><br style="font-family:Courier New"><font face="courier new">&nbsp;&nbsp; &nbsp;glShadeModel(GL_FLAT);</font><br style="font-family:Courier New"><font face="courier new">&nbsp;&nbsp; &nbsp;glPixelStorei(GL_UNPACK_ALIGNMENT, 1);</font><br style="font-family:Courier New"><br style="font-family:Courier New"><font face="courier new">&nbsp;&nbsp; &nbsp;// Texture initialization</font><br style="font-family:Courier New"><font face="courier new">&nbsp;&nbsp; &nbsp;glGenTextures(1, &amp;textureName);</font><br style="font-family:Courier New"><font face="courier new">&nbsp;&nbsp; &nbsp;glBindTexture(GL_TEXTURE_2D, textureName);</font><br style="font-family:Courier New"><br style="font-family:Courier New"><font face="courier new">&nbsp;&nbsp; &nbsp;glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);</font><br style="font-family:Courier New"><font face="courier new">&nbsp;&nbsp; &nbsp;glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);</font><br style="font-family:Courier New"><font face="courier new">&nbsp;&nbsp; &nbsp;glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);&nbsp;&nbsp; &nbsp;// GL_NEAREST is another choice</font><br style="font-family:Courier New"><font face="courier new">&nbsp;&nbsp; &nbsp;glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);</font><br style="font-family:Courier New"><br style="font-family:Courier New"><font face="courier new">&nbsp;&nbsp; &nbsp;glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, m_nWidth, m_nHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, texImage);</font><br style="font-family:Courier New"><font face="courier new">}</font></font></font><br><br><br>To draw a 2D image as a texture, we have to map image coordinates to texture coordinates when we draw GL_QUADS.<br>In the following function, we map the texture created in <font size="2"><font face="courier new">initializeGL</font></font> to rectangular coordinates -1.0 to 1.0.<br><br><font size="2"><font face="courier new">void GLTexture2D::paintGL() {</font><br style="font-family:Courier New"><font face="courier new">&nbsp;&nbsp;&nbsp; glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);</font><br style="font-family:Courier New"><font face="courier new">&nbsp;&nbsp;&nbsp; glEnable(GL_TEXTURE_2D);</font><br style="font-family:Courier New"><font face="courier new">&nbsp;&nbsp;&nbsp; glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);</font><br style="font-family:Courier New"><font face="courier new">&nbsp;&nbsp;&nbsp; glBindTexture(GL_TEXTURE_2D, textureName);</font><br style="font-family:Courier New"><br style="font-family:Courier New"><font face="courier new">&nbsp;&nbsp;&nbsp; glBegin(GL_QUADS);</font><br style="font-family:Courier New"><font face="courier new">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;glTexCoord2f(0.0, 0.0);&nbsp;&nbsp;&nbsp; glVertex3f(-1.0, -1.0, 0.0);</font><br style="font-family:Courier New"><font face="courier new">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;glTexCoord2f(0.0, 1.0);&nbsp; &nbsp; glVertex3f(-1.0,&nbsp; 1.0, 0.0);</font><br style="font-family:Courier New"><font face="courier new">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;glTexCoord2f(1.0, 1.0);&nbsp; &nbsp; glVertex3f( 1.0,&nbsp; 1.0, 0.0);</font><br style="font-family:Courier New"><font face="courier new">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;glTexCoord2f(1.0, 0.0);&nbsp; &nbsp; glVertex3f( 1.0, -1.0, 0.0);</font><br style="font-family:Courier New"><font face="courier new">&nbsp;&nbsp;&nbsp; glEnd();</font><br style="font-family:Courier New"><font face="courier new">&nbsp;&nbsp;&nbsp; glDisable(GL_TEXTURE_2D);</font><br style="font-family:Courier New"><font face="courier new">}</font></font><br><br>===================================<br><br>An example project for Eclipse CDT / Qt on Linux is stored at <a href="http://cid-a4f67aec001a7049.skydrive.live.com/self.aspx/plaza/OpenGL/GLTexture2D.zip" id="r0dm" title="a public folder here">a public folder here</a>.<br>The project file is valid for Eclipse CDT on Linux with Qt integration (Ubuntu 9.04 Juanty), but the main part should be applicable to most C++ environment.<br><br><br>Pinyo Taeprasartsit<br>Octobor 2009<br>pinyotaehttp://www.blogger.com/profile/08056348551542825367noreply@blogger.com0tag:blogger.com,1999:blog-7454278.post-86218150312809632762010-06-12T14:20:00.001-04:002010-06-12T14:20:51.684-04:00glDrawPixels + Qt (Part 3)<h1>glDrawPixels + Qt (Part 3)</h1>In this part, we will discuss the use of a pixel buffer in OpenGL.&nbsp; A pixel buffer is an advanced feature, which is aimed at increasing screen draw rate.<br>For OpenGL 2.1, this pixel buffer is a part of a standard extension and not in OpenGL core.&nbsp; <br><br>To use this extension, things become much more complicated, but can still be explained step by step, as follows.<br><ol><li>We need to include &lt;GL/glew.h&gt; before any other OpenGL context.&nbsp; In Qt, we can normally include it in a header file before we include any QGLWidget.<br>For your information, this extension is <a href="http://en.wikipedia.org/wiki/OpenGL_Extension_Wrangler_Library" id="tpad" title="OpenGL Extension Wrangler Library (GLEW)">OpenGL Extension Wrangler Library (GLEW)</a>.<br><br></li><li>Since GLEW is a library, we have to declare its use in a .pro file.&nbsp; Open a .pro file and add a line<br><font size="1"><br><font face="courier new"><font size="2">LIBS&nbsp;&nbsp; &nbsp;+= -lGLEW</font></font></font><br><br>Your project can now link to this library properly.<br><br></li><li>Initialize GLEW before any other OpenGL work.&nbsp; This should be done in the initializeGL method of QGLWidget.<br>Initializing GLEW, however, may fail, especially if we try to initialize it for the second time.<br>Thus, it is recommended to prepare for initialization error, as shown below.<br><font size="1"><br style="font-family:Courier New"><font size="2"><font face="courier new">GLenum initStatus = glewInit();</font><br style="font-family:Courier New"><font face="courier new">if (initStatus != GLEW_OK) {</font><br style="font-family:Courier New"><font face="courier new">&nbsp;&nbsp;&nbsp; cout &lt;&lt; &quot;Cannot initialize glew.&quot; &lt;&lt; endl;</font><br style="font-family:Courier New"><font face="courier new">&nbsp;&nbsp;&nbsp; exit(1);</font><br style="font-family:Courier New"><font face="courier new">} else</font><br style="font-family:Courier New"><font face="courier new">&nbsp;&nbsp;&nbsp; cout &lt;&lt; &quot;glew is successfully initialized.&quot; &lt;&lt; endl;</font></font></font><br><br></li><li><font size="2"><font face="verdana">Bind data to a buffer.&nbsp; We need to provide a non-local </font></font>GLuint to be employed as a buffer ID.&nbsp; This may be a class-member or global variable.<br>Assume that we declare the ID variable as a class member by<br><br><font face="courier new">GLuint pixelBuffer;</font><br><br>Next, bind the buffer to it.&nbsp; Note that chkImage contains pixel data and must be already filled.<br>These patch of code is still in initializeGL.<br><br><font face="courier new">glGenBuffers(1, &amp;pixelBuffer);</font><br style="font-family:Courier New"><font face="courier new">glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pixelBuffer);</font><br style="font-family:Courier New"><font face="courier new">glBufferData(GL_PIXEL_UNPACK_BUFFER, 3* m_nWidth * m_nHeight, chkImage,</font><br style="font-family:Courier New"><font face="courier new">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; GL_STATIC_DRAW);</font><br><br></li><li><font size="1"><font size="2"><font face="verdana">Draw pixels in paintGL by</font></font><br><font size="2"><br></font><font size="2"><font face="courier new">GLubyte* nBuffOffset = 0;</font><br style="font-family:Courier New"><font face="courier new">glDrawPixels(m_nWidth, m_nHeight, GL_RGB, GL_UNSIGNED_BYTE, nBuffOffset);</font></font></font><br><br>Note that instead of providing a pointer to chkImage, we provide an offset in a buffer.&nbsp; The zero offset means that we are going to use the first byte of the buffer and so on.<br><br>To make this matter more understandable in terms of actual implementation, methods for initialization and painting are shown below.<br><br><font size="1"><font size="2"><font face="courier new">void GLImage2_2::initializeGL()</font><br style="font-family:Courier New"><font face="courier new">{</font><br style="font-family:Courier New"><font face="courier new">&nbsp;&nbsp; &nbsp;GLenum initStatus = glewInit();</font><br style="font-family:Courier New"><font face="courier new">&nbsp;&nbsp; &nbsp;if (initStatus != GLEW_OK) {</font><br style="font-family:Courier New"><font face="courier new">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;cout &lt;&lt; &quot;Cannot initialize glew.&quot; &lt;&lt; endl;</font><br style="font-family:Courier New"><font face="courier new">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;exit(1);</font><br style="font-family:Courier New"><font face="courier new">&nbsp;&nbsp; &nbsp;} else</font><br style="font-family:Courier New"><font face="courier new">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;cout &lt;&lt; &quot;glew is successfully initialized.&quot; &lt;&lt; endl;</font><br style="font-family:Courier New"><br style="font-family:Courier New"><font face="courier new">&nbsp;&nbsp; &nbsp;// Set coordinate system</font><br style="font-family:Courier New"><font face="courier new">&nbsp;&nbsp; &nbsp;glOrtho(0, m_nWidth, 0, m_nHeight, 0, 1);</font><br style="font-family:Courier New"><br style="font-family:Courier New"><font face="courier new">&nbsp;&nbsp; &nbsp;// Basic initialization</font><br style="font-family:Courier New"><font face="courier new">&nbsp;&nbsp; &nbsp;glClearColor(0.0, 0.0, 0.0, 0.0);</font><br style="font-family:Courier New"><font face="courier new">&nbsp;&nbsp; &nbsp;glShadeModel(GL_FLAT);</font><br style="font-family:Courier New"><font face="courier new">&nbsp;&nbsp; &nbsp;glPixelStorei(GL_UNPACK_ALIGNMENT, 1);</font><br style="font-family:Courier New"><br style="font-family:Courier New"><font face="courier new">&nbsp;&nbsp; &nbsp;// Using buffer objects</font><br style="font-family:Courier New"><font face="courier new">&nbsp;&nbsp; &nbsp;glGenBuffers(1, &amp;pixelBuffer);</font><br style="font-family:Courier New"><font face="courier new">&nbsp;&nbsp; &nbsp;glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pixelBuffer);</font><br style="font-family:Courier New"><font face="courier new">&nbsp;&nbsp; &nbsp;glBufferData(GL_PIXEL_UNPACK_BUFFER, 3* m_nWidth * m_nHeight, chkImage,</font><br style="font-family:Courier New"><font face="courier new">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;GL_STATIC_DRAW);</font><br style="font-family:Courier New"><font face="courier new">}</font><br><br><br style="font-family:Courier New"><br><br><font face="courier new">void GLImage2_2::paintGL() {</font><br style="font-family:Courier New"><font face="courier new">&nbsp;&nbsp;&nbsp; glClear(GL_COLOR_BUFFER_BIT);</font><br style="font-family:Courier New"><font face="courier new">&nbsp;&nbsp;&nbsp; glRasterPos2i(0, 0);</font><br style="font-family:Courier New"><br style="font-family:Courier New"><font face="courier new">&nbsp;&nbsp;&nbsp; GLubyte* nBuffOffset = 0;</font><br style="font-family:Courier New"><font face="courier new">&nbsp;&nbsp;&nbsp; glDrawPixels(m_nWidth, m_nHeight, GL_RGB, GL_UNSIGNED_BYTE, nBuffOffset);</font><br style="font-family:Courier New"><font face="courier new">}</font></font><br style="font-family:Courier New"></font></li></ol><br>So, what if we have several buffers?&nbsp; In that case, we have to prepare more buffer-ID variables, bind them, and populate them.&nbsp; <br>At the painting time, we specify our target buffer.&nbsp; For concreateness, see the code below.<br><br><font size="2"><font face="courier new">void GLImage2_2::paintGL() {</font><br style="font-family:Courier New"><font face="courier new">&nbsp;&nbsp;&nbsp; glClear(GL_COLOR_BUFFER_BIT);</font><br style="font-family:Courier New"><font face="courier new">&nbsp;&nbsp;&nbsp; glRasterPos2i(0, 0);</font><br style="font-family:Courier New"><br><font face="courier new">&nbsp;&nbsp;&nbsp; if (target = 0)<br>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;</font></font><font size="2"><font face="courier new">glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pixelBuffer1);</font></font><font size="2"><br><font face="courier new">&nbsp;&nbsp;&nbsp; else<br>&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;</font></font><font size="2"><font face="courier new">glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pixelBuffer2);</font></font><font size="2"><br><br style="font-family:Courier New"><font face="courier new">&nbsp;&nbsp;&nbsp; GLubyte* nBuffOffset = 0;</font><br style="font-family:Courier New"><font face="courier new">&nbsp;&nbsp;&nbsp; glDrawPixels(m_nWidth, m_nHeight, GL_RGB, GL_UNSIGNED_BYTE, nBuffOffset);</font><br style="font-family:Courier New"><font face="courier new">}</font><br></font><br>===================================<br><br>An example Eclipse CDT / Qt project is stored at <a href="http://cid-a4f67aec001a7049.skydrive.live.com/self.aspx/plaza/OpenGL/GLImage2%5E_2.zip" id="r0dm" title="a public folder here">a public folder here</a>.<br>The project file is valid for Eclipse CDT on Linux with Qt integration (Ubuntu 9.04 Juanty), but the main part should be applicable to most C++ environment.<br><br><br>Pinyo Taeprasartsit<br>September 2009<br>pinyotaehttp://www.blogger.com/profile/08056348551542825367noreply@blogger.com0tag:blogger.com,1999:blog-7454278.post-30696341541506558342010-06-12T14:13:00.001-04:002010-06-12T14:13:42.478-04:00glDrawPixels + Qt (Part 2)<h1>glDrawPixels + Qt (Part 2)</h1>In this part, we are going to use Qt to load an image from a file and display it with QGLWidget by using glDrawPixels.<br>The process is generally the same, except the order of function calls and the use of Qt to load an image file.<br><br>First, take a look at the constructor<br><font size="1"><br><font face="courier new"><font size="2">GLImage2_1::GLImage2_1(QGLWidget *parent)</font></font><font size="2"><br style="font-family:Courier New"><font face="courier new">&nbsp;&nbsp;&nbsp; : QGLWidget(parent)</font><br style="font-family:Courier New"><font face="courier new">{</font><br style="font-family:Courier New"><font face="courier new">&nbsp;&nbsp; &nbsp;makeImage();</font><br style="font-family:Courier New"><font face="courier new">&nbsp;&nbsp; &nbsp;m_nCurrWidth = m_nWidth;</font><br style="font-family:Courier New"><font face="courier new">&nbsp;&nbsp; &nbsp;m_nCurrHeight = m_nHeight;</font><br style="font-family:Courier New"><font face="courier new">}</font></font></font><br><br>The function makeImage() is called early because we want to know image dimensions and give a correct size hint to a QGLWidget.<br>initializeGL is, therefore, leaner.<br><font size="1"><br style="font-family:Courier New"><font size="2"><font face="courier new">void GLImage2_1::initializeGL()</font><br style="font-family:Courier New"><font face="courier new">{</font><br style="font-family:Courier New"><font face="courier new">&nbsp;&nbsp; &nbsp;// Set coordinate system</font><br style="font-family:Courier New"><font face="courier new">&nbsp;&nbsp; &nbsp;glOrtho(0, m_nWidth, 0, m_nHeight, 0, 1);</font><br style="font-family:Courier New"><br style="font-family:Courier New"><font face="courier new">&nbsp;&nbsp; &nbsp;// Basic initialization</font><br style="font-family:Courier New"><font face="courier new">&nbsp;&nbsp; &nbsp;glClearColor(0.0, 0.0, 0.0, 0.0);</font><br style="font-family:Courier New"><font face="courier new">&nbsp;&nbsp; &nbsp;glShadeModel(GL_FLAT);</font><br style="font-family:Courier New"><font face="courier new">&nbsp;&nbsp; &nbsp;glPixelStorei(GL_UNPACK_ALIGNMENT, 1);</font><br style="font-family:Courier New"><font face="courier new">}</font></font></font><br><br>Now, let&#39;s get to makeImage(), the most important part of this article.<br><br><font size="2"><font face="courier new">void GLImage2_1::makeImage() {</font><br style="font-family:Courier New"><font face="courier new">&nbsp;&nbsp; &nbsp;string fileName(&quot;/home/pinyo/temp/beach.jpg&quot;);</font><br style="font-family:Courier New"><br style="font-family:Courier New"><font face="courier new">&nbsp;&nbsp; &nbsp;QImage qImage;</font><br style="font-family:Courier New"><font face="courier new">&nbsp;&nbsp; &nbsp;qImage.load(QString(fileName.c_str()));</font><br style="font-family:Courier New"><br style="font-family:Courier New"><font face="courier new">&nbsp;&nbsp; &nbsp;m_nWidth = qImage.width();</font><br style="font-family:Courier New"><font face="courier new">&nbsp;&nbsp; &nbsp;m_nHeight = qImage.height();</font><br style="font-family:Courier New"><br style="font-family:Courier New"><font face="courier new">&nbsp;&nbsp; &nbsp;chkImage = new GLubyte[m_nHeight * m_nWidth * 3];</font><br style="font-family:Courier New"><br style="font-family:Courier New"><font face="courier new">&nbsp;&nbsp; &nbsp;for (int h = 0; h &lt; m_nHeight; ++h) {</font><br style="font-family:Courier New"><font face="courier new">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;int nImgH = m_nHeight - h - 1;</font><br style="font-family:Courier New"><br style="font-family:Courier New"><font face="courier new">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;for (int w = 0; w &lt; m_nWidth; ++w) {</font><br style="font-family:Courier New"><font face="courier new">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;QRgb color = qImage.pixel(w, nImgH);</font><br style="font-family:Courier New"><br style="font-family:Courier New"><font face="courier new">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;chkImage[3* (h *m_nWidth + w) + 0] = (GLubyte) qRed(color);</font><br style="font-family:Courier New"><font face="courier new">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;chkImage[3*(h*m_nWidth + w) + 1] = (GLubyte) qGreen(color);</font><br style="font-family:Courier New">&nbsp;&nbsp;<font face="courier new"> &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;chkImage[3*(h*m_nWidth + w) + 2] = (GLubyte) qBlue(color);</font><br style="font-family:Courier New"><font face="courier new">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;}</font><br style="font-family:Courier New"><font face="courier new">&nbsp;&nbsp; &nbsp;}</font><br style="font-family:Courier New"><br style="font-family:Courier New"><font face="courier new">&nbsp;&nbsp;&nbsp; return;</font><br style="font-family:Courier New"><font face="courier new">}</font><br style="font-family:Courier New"></font><br><b>There are a few things we have to pay attention to.</b><br><ol><li>QImage is used and (declared in qimage.h)</li><li>We have no need to explicitly supply the image file type to its load function.&nbsp; Qt first relies on file extension (.jpg, .png, for example).&nbsp; If it fails or there is no file extension, Qt will make a guess based on file header.</li><li>Notice the use of <font size="1"><font face="courier new">int nImgH = m_nHeight - h - 1;&nbsp; <font size="2"><font face="verdana">This is essential because <b>the image coordinate system in OpenGL is different from most computer imaging systems</b>, including</font><font face="verdana"> Qt.&nbsp; In Qt the origin is at top left and the y-axis points downward, while in OpenGL</font></font>,<font size="2"><font face="verdana"> the origin is at bottom left and the y-axis points upward.&nbsp; Since the x-axes in Qt and OpenGL are</font><font face="verdana"> the same, there is no need to convert x-coordinates</font></font>.<br></font></font></li></ol><br><br>========================================<br><br>An example Eclipse CDT / Qt project is stored at <a href="http://cid-a4f67aec001a7049.skydrive.live.com/self.aspx/plaza/OpenGL/GLImage2%5E_1.zip" id="r0dm" title="a public folder here">a public folder here</a>.<br> The project file is valid for Eclipse CDT on Linux with Qt integration (Ubuntu 9.04 Juanty), but the main part should be applicable to most C++ environment.<br><br><br>Pinyo Taeprasartsit<br>September 2009<br>pinyotaehttp://www.blogger.com/profile/08056348551542825367noreply@blogger.com1tag:blogger.com,1999:blog-7454278.post-47189420154228679952010-06-12T14:11:00.001-04:002010-06-12T14:11:22.271-04:00glDrawPixels + Qt (Part 1)<h1>glDrawPixels + Qt (Part 1)</h1>This is an article following <a href="http://docs.google.com/View?id=dggq8h5d_198hjx8c8gq" id="zr2e" title="GL_POINTS + Qt">GL_POINTS + Qt</a>.&nbsp; As mentioned earlier, we can use glDrawPixels with glPixelZoom to deal with 2D graphics.<br>Although it appears to be more complicated than GL_POINTS, glDrawPixels is still another simple method.<br><br>The strength of glDrawPixels is its ability to scale an image in a way most people expect.&nbsp; For example, a pixel in the original scale may occupy more than one pixel in a window, if the window is scaled up.<br>We can also increase draw rate by using buffer, but Part 1 will not cover that topic.<br><br>Now, let&#39;s see how to draw an image by using glDrawPixels and glPixelZoom.&nbsp; Recall that the coordinate system of OpenGL may be different from most imaging systems.&nbsp; OpenGL set the origin at the bottom left by default.<br><br>The major difference between GL_POINTS and glDrawPixels is that GL_POINTS is based on a call list, while glDrawPixels is based on an array.<br>This array is a flatten 3D or 4D array.&nbsp; Namely, RGB(A) data is kept together in a 1D array.&nbsp; We have to tell OpenGL a color model we want to use.<br><br>Assume that we want to use the RGB color model and the image is of size 128x128 pixels.&nbsp; Therefore, we have to create a 1D array of size 128x128x3.&nbsp; RGB values of one pixels are packed at contiguous array cells, as shown below.<br><font face="courier new" size="1"><br><font size="2">/// Build a checker board, each grid cell is of size 16 x 16 pixels.<br>/// </font></font><font size="2"><font face="courier new">0x10 is a base-16 number equal to 16.</font><br></font><font size="2"><font face="courier new">void GLImage::makeImage() {</font><br style="font-family:Courier New"><font face="courier new">&nbsp;&nbsp; &nbsp;chkImage = new GLubyte[m_nHeight * m_nWidth * 3];</font><br style="font-family:Courier New"><br style="font-family:Courier New"><font face="courier new">&nbsp;&nbsp; &nbsp;int c;</font><br style="font-family:Courier New"><font face="courier new">&nbsp;&nbsp; &nbsp;for (int h = 0; h &lt; m_nHeight; ++h)</font><br style="font-family:Courier New"><font face="courier new">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;for (int w = 0; w &lt; m_nWidth; ++w) {</font><br style="font-family:Courier New"><font face="courier new">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;c = ( ((h&amp;0x10) == 0)^((w&amp;0x10) == 0) )*255;</font><br style="font-family:Courier New"><font face="courier new">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;chkImage[3*(h*m_nWidth + w) + 0] = (GLubyte) c;</font><br style="font-family:Courier New"><font face="courier new">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;chkImage[3*(h*m_nWidth + w) + 1] = (GLubyte) c;</font><br style="font-family:Courier New"><font face="courier new">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;chkImage[3*(h*m_nWidth + w) + 2] = (GLubyte) c;</font><br style="font-family:Courier New"><font face="courier new">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;}</font><br style="font-family:Courier New"><br style="font-family:Courier New"><font face="courier new">&nbsp;&nbsp;&nbsp; return;</font><br style="font-family:Courier New"><font face="courier new">}</font></font><br><br>The drawing process is super easy.<br><br><font size="2"><font face="courier new">void GLImage::paintGL() {</font><br style="font-family:Courier New"><font face="courier new">&nbsp;&nbsp;&nbsp; glClear(GL_COLOR_BUFFER_BIT);</font><br style="font-family:Courier New"><font face="courier new">&nbsp;&nbsp;&nbsp; glRasterPos2i(0, 0);</font><br style="font-family:Courier New"><font face="courier new">&nbsp;&nbsp;&nbsp; glDrawPixels(m_nWidth, m_nHeight, GL_RGB, GL_UNSIGNED_BYTE, chkImage);</font><br style="font-family:Courier New"><font face="courier new">}</font><br></font><br>The resize process needs to specify zoom factors for both x- and y-axes.&nbsp; Note that we may not need to use m_nCurrWidth and m_nCurrHeight, if we do not intend to use them for other proposed.<br><br><font size="2"><font face="courier new">void GLImage::resizeGL(int width, int height) {</font><br style="font-family:Courier New"><font face="courier new">&nbsp;&nbsp; &nbsp;glViewport(0, 0, width, height);</font><br style="font-family:Courier New"><font face="courier new">&nbsp;&nbsp; &nbsp;m_nCurrWidth = width;</font><br style="font-family:Courier New"><font face="courier new">&nbsp;&nbsp; &nbsp;m_nCurrHeight = height;</font><br style="font-family:Courier New"><br style="font-family:Courier New"><font face="courier new">&nbsp;&nbsp; &nbsp;glPixelZoom(m_nCurrWidth / (double) m_nWidth, m_nCurrHeight / (double) m_nHeight);</font><br style="font-family:Courier New"><font face="courier new">}</font></font><br><br>The way for initialization may be a bit more complicated than usual, but it is a pattern we can just follow (somewhat blindly).<br><font size="1"><br style="font-family:Courier New"><font size="2"><font face="courier new">void GLImage::initializeGL()</font><br style="font-family:Courier New"><font face="courier new">{</font><br style="font-family:Courier New"><font face="courier new">&nbsp;&nbsp; &nbsp;glClearColor(0.0, 0.0, 0.0, 0.0);</font><br style="font-family:Courier New"><br style="font-family:Courier New"><font face="courier new">&nbsp;&nbsp; &nbsp;glMatrixMode(GL_PROJECTION);</font><br style="font-family:Courier New"><font face="courier new">&nbsp;&nbsp; &nbsp;glLoadIdentity();</font><br style="font-family:Courier New"><font face="courier new">&nbsp;&nbsp; &nbsp;glOrtho(0, m_nWidth, 0, m_nHeight, 0, 1);</font><br style="font-family:Courier New"><font face="courier new">&nbsp;&nbsp; &nbsp;glMatrixMode(GL_MODELVIEW);</font><br style="font-family:Courier New"><br style="font-family:Courier New"><font face="courier new">&nbsp;&nbsp; &nbsp;glShadeModel(GL_FLAT);</font><br style="font-family:Courier New"><font face="courier new">&nbsp;&nbsp;&nbsp; makeImage();</font><br style="font-family:Courier New"><font face="courier new">&nbsp;&nbsp;&nbsp; glPixelStorei(GL_UNPACK_ALIGNMENT, 1);</font><br style="font-family:Courier New"><font face="courier new">}</font></font></font><br><br>Notice the use of glShadeModel(GL_FLAT).&nbsp; glPixelStorei is employed to specify the way we store color data.&nbsp; The parameter 1 indicates that it is 1-btye alignment.&nbsp; Basically, there is no restriction of the beginning position of each row with this parameter.&nbsp; If it is 2, each row must start on even-numbered byte.<br><br><br>========================================<br><br>An example Eclipse CDT / Qt project is stored at <a href="http://cid-a4f67aec001a7049.skydrive.live.com/self.aspx/plaza/OpenGL/GLImage.zip" id="r0dm" title="a public folder here">a public folder here</a>.<br>The project file is valid for Eclipse CDT on Linux with Qt integration (Ubuntu 9.04 Juanty), but the main part should be applicable to most C++ environment.<br><br><br>Pinyo Taeprasartsit<br> September 2009<br>pinyotaehttp://www.blogger.com/profile/08056348551542825367noreply@blogger.com0tag:blogger.com,1999:blog-7454278.post-61542861764010533582010-05-25T20:10:00.002-04:002010-05-25T20:49:28.351-04:00Eclise + MinGW + FreeGlut (2)<h1>Eclipse CDT + MinGW + FreeGlut (2)</h1>This tutorial starts with building freeglut to create a simple working application with Eclipse and MinGW in both 32-bit and 64-bit versions.&nbsp; This tutorial refers to a few other tutorials so that readers can jump to the part they want to know conveniently.&nbsp; Follow the instructions below is relatively a simple task.<br><br><ol><li>The first task is to obtain Eclipse CDT.&nbsp; This tutorial is based on Eclipse CDT Galieo (SR2 Build ID:2010 02 18-1602).&nbsp; You can download it from <a href="http://www.eclipse.org/downloads/download.php?file=/technology/epp/downloads/release/galileo/SR2/eclipse-cpp-galileo-SR2-win32.zip" id="a_88" title="this link">this link</a>, but the most recent version on the Eclipse server may be your preferred choice.<br><br></li><li>Obtain your preferred MinGW version.&nbsp; I prepared <a href="http://docs.google.com/leaf?id=0B-WlB8Fgc324Njk0NDE3ZWItMDMzZS00YjI1LWFkNzEtZmNmZTFiOGU4OWUy&amp;sort=name&amp;layout=list&amp;num=50" id="ktkh" title="32-bit MinGW 4.5.0">32-bit MinGW 4.5.0</a> and <a href="http://docs.google.com/leaf?id=0B-WlB8Fgc324NTI3ODNhNWItZjQyNi00ODNhLWI3YzgtNDkxZTA1YWUzODNl&amp;sort=name&amp;layout=list&amp;num=50" id="lv72" title="64-bit MinGW 4.6.0 (2010-April-16 Experimental)">64-bit MinGW 4.6.0 (2010-April-16 Experimental)</a> packages for you to download.&nbsp; Note that the include paths within the packages are different.&nbsp; This is the default settings of the two packages.&nbsp; Eclipse, however, knows the 32-bit folder paths well, but does not aware of the include paths for the 64-bit version.&nbsp; Probably, this is because the 64-bit version is still experimental. <br><br></li><li>Download <a href="http://freeglut.sourceforge.net/" id="fykr" title="FreeGlut">freeglut</a>.&nbsp; This tutorial uses freeglut 2.6.0.&nbsp; If you want to use a pre-compiled binary package, try the following links.</li><ol><li><a href="http://cid-a4f67aec001a7049.skydrive.live.com/self.aspx/plaza/OpenGL/freeglut/FreeGlut-2.6.0-MinGW-32bit-O2.zip" id="qjmn" title="freeglut 32-bit">freeglut 32-bit</a>, compiled with 32-bit MinGW 4.5.0 (O2 optimization).&nbsp; libfreeglut32.a and freeglut32.dll are for dynamic linking, while libfreeglut32_static.a is for static linking.&nbsp; Header files are included.&nbsp; I built this package myself.&nbsp; Feel free to contact me if you have any problem (use the comment in my blog)<br><br></li><li><a href="http://cid-a4f67aec001a7049.skydrive.live.com/self.aspx/plaza/OpenGL/freeglut/FreeGlut-2.6.0-MinGW-64bit-O2.zip" id="c0r3" title="freeglut 64-bit">freeglut 64-bit</a>, compiled with 64-bit MinGW 4.6.0 (2010-April-16 Experimental) (O2 optimization).&nbsp; libfreeglut64.a and freeglut64.dll are for dynamic linking, while libfreeglut64_static.a is for static linking.&nbsp; Header files are included.&nbsp; I built this package myself.&nbsp; Feel free to contact me if you have any problem (use the comment in my blog)<br><br></li><li><a href="http://www.transmissionzero.co.uk/computing/using-glut-with-mingw/" id="h6j9" title="Other source">From other source</a><br><br></li></ol><li>Build freeglut (If you get the binary package from Step 3, ignore this step).&nbsp; Instructions are available in <a href="http://docs.google.com/View?id=dggq8h5d_496gzdt6dgz" id="jyom" title="my post">my post</a> and in <a href="http://netsuperbrain.com/blog/posts/freeglut-windows-hopengl-hglut/" id="p4tw" title="another web site">another web site</a>.<br><br></li><li>Putting things together.&nbsp; If you use MinGW and freeglut 32-bit, this step is quite simple, as Eclipse knows MinGW 32-bit settings well, provided that you save MinGW at C:\MinGW. If you choose a 64-bit path, follow a common instruction for <a href="http://docs.google.com/View?id=dggq8h5d_494hnb5n5qk" id="rxtf" title="building 64-bit applications with Eclipse + MinGW 64-bit in my post">building and running 64-bit applications with Eclipse + MinGW 64-bit in my post</a>.</li><ol><li>Put freeglut library in a proper place.</li><li>Set compiler and linker flags.&nbsp; This can be done by going to &#39;Project-&gt;Properties&#39;.&nbsp; Then, in C/C++ Build, go to &#39;Settings&#39;.&nbsp; The flags for static and dynamic links are different.&nbsp; I assume that you are going to build a C++ application.<br></li><ol><li><b>For static link</b>: <br>In &#39;GCC C++ Compiler&#39;, go to &#39;Preprocessor&#39; and add a defined symbol FREEGLUT_STATIC.&nbsp; Also, make sure that your compiler see your freeglut and OpenGL headers.<br><br>In &#39;MinGW C++ Linker&#39;, go to &#39;Libraries&#39; and add the following libraries (-l): winmm, gid32, opengl32, and freeglut64_static.&nbsp; Note that the name for freeglut64_static must be consistent with your actual library file name.&nbsp; Also, it is important to omit the prefix &#39;lib&#39; and suffix &#39;.a&#39;.&nbsp; It is crucial, however, that the library file name must come with the prefix and suffix.&nbsp; Next, add library search path (-L).&nbsp; This is where you have placed your freeglut library.&nbsp; For example, in my case, I add a path &quot;C:\MinGW_x64\x86_64-w64-mingw32\lib\freeglut&quot; (with double quotes).<br><br></li><li><b>For dynamic link</b>:<br>There is no need to add any thing to the preprocessor section, but make sure that your compiler see your freeglut and OpenGL headers.<br><br>Now, go to &#39;MinGW C++ Linker&#39; and its library section.&nbsp; Then, do exactly the same thing as discussed for the static link, except that you have to change freeglut64_static to the one for your dynamic link.<br><br></li></ol><li>Build application.&nbsp; Try starting with a simple one.&nbsp; A good example is given from other <a href="http://www.transmissionzero.co.uk/computing/using-glut-with-mingw/" id="l_qs" title="web site"></a><a href="http://www.transmissionzero.co.uk/computing/using-glut-with-mingw/" id="tgln" title="www.transmissionzero.co.uk">www.transmissionzero.co.uk</a>.<br><br></li><li>Run your application.&nbsp; This seems to be trivial at first, but it can be a bit tricky because you also have to set your MinGW library path.&nbsp; In addition, if you dynamically link to freeglut, you need to set up its library path.&nbsp; Whether or not you are building an 64-bit application, please see <a href="http://pinyotae.blogspot.com/2010/05/eclipse-mingw-x64.html" id="yfrt" title="Section &#39;Change Run-Time Setting&#39; in my previous post">Section &#39;Change Run-Time Setting&#39; in my previous post</a>.&nbsp; It shows you how to set run-time library paths in Eclipse and Windows command to set a library path in case that you are going to run your application outside Eclipse.&nbsp; If you feel not understand how to do it, you might want to check some figures in <a href="http://pinyotae.blogspot.com/2008/05/eclipse-cdt-mingw-freeglut.html" id="ruce" title="my even older post">my even older post</a> (Figures 6 and 7).<br></li></ol></ol><br>Pinyo Taeprasartsit<br>(May 2010)<br><br>This document can be viewed at <a href="http://pinyotae.blogspot.com/2010/05/eclise-mingw-freeglut.html" id="tsrj" title="my blog">my blog</a> and <a href="http://docs.google.com/View?id=dggq8h5d_497dv9tpdcr" id="thlw" title="my Google docs">my Google docs</a>.&nbsp; I welcome questions, comments, and suggestions.&nbsp; Please leave a message in <a href="http://pinyotae.blogspot.com/2010/05/eclise-mingw-freeglut.html" id="tym0" title="my blog">my blog</a> if you have any.&nbsp; Thank you.<br><br><br><br>pinyotaehttp://www.blogger.com/profile/08056348551542825367noreply@blogger.com8tag:blogger.com,1999:blog-7454278.post-68772488982241563002010-05-25T19:17:00.003-04:002011-01-23T00:55:28.403-04:00Build FreeGlut with MinGW<h1>Build FreeGlut with MinGW</h1>(updated Jan 21, 2011: new FreeGlut 64-bit pre-compiled binary is now available. This solves a naming issue caused by an earlier version of MinGW. Thank you James for pointing out the issue.)<br /><br />FreeGlut 2.6.0 comes with Visual Studio 2008 solution files. If you use Visual Studio, you can probably build the package easily. If you, however, want to use MinGW to build FreeGlut (either or both 32-bit and 64-bit versions), you may not know where to start. Thus, I wrote this document, so that you can build FreeGlut yourself. If you prefer, there are several binary packages ready to use in some web sites. Example of these web sites are http://www.transmissionzero.co.uk/software/freeglut-devel/ and this web site itself.<br /><br /><h3>32-Bit FreeGlut</h3>Use MSYS to build 32-bit freeglut shared library [<a href="http://netsuperbrain.com/blog/posts/freeglut-windows-hopengl-hglut/" id="qbb4" title="ref: http://netsuperbrain.com/blog/posts/freeglut-windows-hopengl-hglut/">ref: http://netsuperbrain.com/blog/posts/freeglut-windows-hopengl-hglut/</a>]<br /><ol><li>gcc -O2 -c -DFREEGLUT_EXPORTS *.c -I../include</li><li>gcc -shared -o freeglut32.dll *.o -Wl,--enable-stdcall-fixup,--out-implib,libfreeglut32.a -lopengl32 -lglu32 -lgdi32 -lwinmm<br /></li></ol><br />Use MSYS to build 32-bit freeglut static library<br /><ol><li>gcc -O2 -c -DFREEGLUT_STATIC *.c -I../include (same as above, except the flag is changed from FREEGLUT_EXPORTS to FREEGLUT_STATIC)<br /></li><li>ar rcs libfreeglut32_static.a *.o [<a href="http://www.adp-gmbh.ch/cpp/gcc/create_lib.html" id="zkdi" title="ref: http://www.adp-gmbh.ch/cpp/gcc/create_lib.html">ref: http://www.adp-gmbh.ch/cpp/gcc/create_lib.html</a>]<br /></li></ol><br />If you want to use a pre-compiled binary package, instead of building it yourself, get a <a href="http://cid-a4f67aec001a7049.skydrive.live.com/self.aspx/plaza/OpenGL/freeglut/FreeGlut-2.6.0-MinGW-32bit-O2.zip" id="ijp3" title="pre-compiled binary package here">pre-compiled binary package here</a>.<br /><br /><h3>64-Bit FreeGlut</h3>This tutorial show a way to build 64-bit FreeGlut by using the Windows command prompt (cmd.exe). Almost every thing is the same as using MSYS for the 32-bit version. In this case, I assume that the current directory is the freeglut source directory and MinGW x64 is at C:\MinGW_x64\bin\.<br /><br />First of all, set PATH to MinGW in the command prompt:<br /><span style="font-family:courier new;">set PATH=%PATH%;C:\mingw_x64\bin</span><br /><br />For a shared library (note that actual prefix gcc-related file names may be different from distribution to distribution)<br /><ol><li style="font-family: Courier New;">x86_64-w64-mingw32-gcc -O2 -c -DFREEGLUT_EXPORTS *.c -I../include</li><li style="font-family: Courier New;">x86_64-w64-mingw32-gcc -shared -o freeglut64.dll *.o -Wl,--enable-stdcall-fixup,--out-implib,libfreeglut64.a -lopengl32 -lglu32 -lgdi32 -lwinmm</li></ol><br />For a static library<br /><ol style="font-family: Courier New;"><li>x86_64-w64-mingw32-gcc -O2 -c -DFREEGLUT_STATIC *.c -I../include <span style="font-family:verdana;">(same as above, except the flag is changed from FREEGLUT_EXPORTS to FREEGLUT_STATIC)</span><br /></li><li>x86_64-w64-mingw32-ar rcs libfreeglut64_static.a *.o</li></ol><br />If you want to use a pre-compiled binary package, instead of building it yourself, get a <a href="http://cid-a4f67aec001a7049.office.live.com/self.aspx/plaza/OpenGL/freeglut/FreeGlut-2.6.0-MinGW-64bit-O2-r2.zip" id="i8tp" title="pre-compiled binary package here">pre-compiled binary package here</a>. This package was built with sezero's build MinGW GCC 4.4.5 20101001.<br /><br />Pinyo Taeprasartsit<br />(May 2010, Jan 2011)<br /><br />This document can be viewed at <a href="http://pinyotae.blogspot.com/2010/05/build-freeglut-with-mingw.html" id="vqw0" title="my blog">my blog</a> and <a href="http://docs.google.com/View?id=dggq8h5d_496gzdt6dgz" id="u:6y" title="my Google docs">my Google docs</a>. Please leave a message in <a href="http://pinyotae.blogspot.com/2010/05/build-freeglut-with-mingw.html" id="j:i2" title="my blog">my blog</a> if you have any questions, comments, and suggestions. Thank you.pinyotaehttp://www.blogger.com/profile/08056348551542825367noreply@blogger.com3tag:blogger.com,1999:blog-7454278.post-39871997749073555052010-05-25T19:10:00.003-04:002010-12-28T05:43:56.914-04:00Eclipse MinGW x64<h1>Eclipse CDT with MinGW w64</h1><p>This tutorial discusses how you can use MinGW 64-bit and Eclipse to build an application.&nbsp; This tutorial is based on 64-bit MinGW (probably version 4.5--the version is not clear from the download page) and Eclipse Galieo (SR2 Build ID:2010 02 18-1602) and Eclipse Helios (SR1 for Windows 64 bit, <font size="2"><span class="filename">eclipse-cpp-helios-SR1-win32-x86_64</span></font>). The following parts of this tutorial assume that you already installed Eclipse and MinGW 64-bit at your preferred paths and will only discuss how you can change Eclipse settings to build and run your applications.</p><h2>Get Compiler</h2>The first task is to obtain a proper MinGW w64 compiler.&nbsp; Although our target platform is Windows 64-bit, the compiler may be a 32-bit application that performs cross-compilation for you.&nbsp; You can choose your preferred version from <a href="http://sourceforge.net/projects/mingw-w64/files/Toolchains%20targetting%20Win64/" id="u90b" title="here">here</a>.&nbsp; There are some significant different for personal and automated builds (as of Dec 2010).&nbsp; For example, the sezero build I used (mingw-w64-bin_x86_64-mingw_20101003_sezero) is 64-bit binary producing 64-bit application, while a binary from the automated build (mingw-w64-1.0-bin_i686-mingw_20101129) is 32-bit binary generating 64-bit application.&nbsp; Technically, the automated build performs cross-compilation, while the sezero build performs native compilation.&nbsp; As sezero build has a conventional directory structures and file names (same as MinGW 32-bit), I recommend using the sezero build.&nbsp; It will save you a lot of time and you will not encounter some naming troubles in later steps.<br><br>In summary, from the link provided above, it is best if you go to the &#39;Personal Builds&#39; section and download the latest sezero build.&nbsp; This is probably the best way to use Windows 64-bit to generate 64-bit applications.<br><h2>Change Compiler Settings (Galieo SR2)</h2><ol><li>Go to menu Project-&gt;Properties.<br><br></li><li>Go to node C/C++ Build-&gt;Environment.<br><br></li><li>Update the path variable according to your MinGW w64 installation.&nbsp; For example, change it to C:\MinGW_w64\bin.&nbsp; <br><br></li><li>Switch to topic C/C++ Build-&gt;Settings.<br><br></li><li><i>[update (Dec 27, 2010): some recent MinGW versions (native compilation) come with &#39;as&#39;, &#39;g++&#39;, and &#39;gcc&#39; commands. This step may be unnecessary for your MinGW build. However, some versions (cross-compilation) still have this issue and this step is required.&nbsp; If you use sezero build, this step is probably unnecessary.]</i><br><br>There are four commands to update: GCC Assembler, GCC C++ Assembler, GCC C Compiler, and MinGW C++ Linker.&nbsp; Correct commands depends on the platform of MinGW w64 you choose.&nbsp; No worry.&nbsp; It is quite obvious to know what commands to use, as the command names are in the format [platform prefix]-[default command].exe.&nbsp; For example, we need to update the command &#39;as&#39;, &#39;g++&#39;, &#39;gcc&#39;, and &#39;g++&#39; for GCC assembler, C++ compiler, C compiler and C++ linker, respectively.&nbsp; The correct commands may be &#39;x86_64-w64-mingw32-as&#39;, &#39;x86_64-w64-mingw32-g++&#39;, &#39;x86_64-w64-mingw32-gcc&#39;, and &#39;x86_64-w64-mingw32-g++&#39;, respectively.<br><br></li></ol><h2>Change Compiler Settings (Helios SR1)</h2>Eclipse Helios is virtually blank regarding compiler configurations, but it seems to be compatible with various GCC toolchains (Mac, Solaris, Cygwin, MinGW, and Linux).&nbsp; Our first task is to choose a proper toolchain as follows.<br><ol><li>Go to menu Project-&gt;Properties.</li><li>Go to node &#39;Tool Chain Editor.&#39; (The spelling of toolchain in Eclipse is not consistent.&nbsp; There are both &#39;tool chain&#39; and &#39;toolchain.&#39;)</li><li>Set the current toolchain to &#39;MinGW GCC.&#39;</li><li>Set the current builder to &#39;CDT Internal Builder.&#39;&nbsp; You are free to use &#39;GNU Make Builder&#39; if you prefer.</li><li>Go to node &#39;Settings.&#39;</li><li>Change the path of compiler/assembler commands.&nbsp; For example, highlight &#39;GCC C++ Compiler&#39; and change the command to &#39;C:\MinGW_64bit\bin\g++&#39; if you save MinGW at C:\MinGW_64bit.<br>&nbsp;</li></ol>There is no path variable any more, but there is a new node called &#39;Discovery Options&#39; inside &#39;C/C++ Build.&#39;&nbsp; If we check &#39;Automate discovery paths and symbols,&#39; most path settings are not necessary during program compilation.<br><br>If you employ OpenMP, you might want to see more detail at <a href="http://www.ipd.uni-karlsruhe.de/multicore/research/download/HowToGuide-OpenMP.pdf" id="zea8" title="this link">this site</a>.&nbsp; Basically, you have to change the miscellaneous flag of GCC C++ Compiler and MinGW C++ Linker to include -fopenmp.&nbsp; Remember, however, that we have to change run-time settings, as OpenMP requires additional run-time libraries.<br><h2>Change Default Include Folders</h2>(This step is required for Galieo, but not for Helios.&nbsp; If you use Helios and choose &#39;Automate discovery paths and symbols&#39; in &#39;C/C++ Build,&#39; the defualt include folders should be correct right of the beginning.)<br><br>It is quite painful in this part, as Eclipse uses the C:/mingw by default.&nbsp; If you have multiple versions of MinGW, you have to change them.&nbsp; Fortunately, (almost) all include files are all the same among versions.&nbsp; Therefore, if we add header files to the default MinGW installation path, things should work across versions.&nbsp; These are, however, the include paths for the Eclipse editor.&nbsp; This means that Eclipse source-code editor can parse and show some hints if we add header files to the default 32-bit MinGW path, even though we are going to use 64-bit MinGW to perform actual program compilation.&nbsp; Therefore, for actual compilation, we need true addendum to an include folder that a compiler uses.&nbsp; See an example below.<br><br>Example: add OpenGL header files to Eclipse for actual compilation.<br>If we want to add header files to a &#39;global&#39; include folder, such as GL, the include folder that will make things work has a platform prefix, say &#39;x86_64-w64-mingw32\include&#39;.&nbsp; This is the case when we call gcc with the same prefix from a bin directory, such as &#39;x86_64-w64-mingw32-gcc.exe&#39;.&nbsp; Addition of header files in other directories has no effect in actual compilation.<br><h2>Change Run-Time Settings</h2>At this step, you can build your 64-bit application, but you probably see that you cannot run it, even within the Eclipse environment itself.&nbsp; Your program might just be terminated without any reported error message.&nbsp; To deal with the problem, you also need to change run-time settings as follows.<br><ol><li>Go to menu &#39;Run-&gt;Run Configurations...&#39;</li><li>Go to tab &#39;Environment&#39;.</li><li>Create a environment variable by using the &#39;New&#39; button.</li><li>In a new popup window, set &#39;Name&#39; to PATH and &#39;Value&#39; to $PATH;C:\MinGW_64bit\bin, provided that C:\MinGW_64bit is the installation folder for your 64-bit MinGW.&nbsp; Note: if you have more paths to include, separate them with a semi-colon.<br><br></li></ol>Alternatively, you can set Windows environment path variable to include the MinGW path.&nbsp; Nonetheless, if you have both 32-bit and 64-bit MinGW in the paths, some DLL names may cause DLL conflict and you may get 32-bit library instead of 64-bit library when you call your program.&nbsp; If your machine, however, has only 64-bit MinGW, using the Windows path variable is probably the most convenient way because you will have no need to create a path variable in Eclipse run-time settings for this purpose again.&nbsp; Nevertheless, dealing with Eclipse run-time settings does not need admin previlage to execute and it is always a viable option.<br><br>Because setting the Eclipse environment variable does not change any path variable outside Eclipse, we cannot run the application by double clicking on it or calling at command prompt, unless path variable for the executable session is set.&nbsp; To temporarily change Windows path variable, a command &#39;<font face="Courier New">set path=%path$;C:\MinGW_64bit\bin&#39;<font face="verdana"> may be used</font> [ref:<a href="http://vlaurie.com/computers2/Articles/environment.htm" id="so5l" title="http://vlaurie.com/computers2/Articles/environment.htm">http://vlaurie.com/computers2/Articles/environment.htm</a>].</font>&nbsp; Again, separate library paths with a semi-colon if you have multiple library paths to add.&nbsp; This effectively appends the MinGW path to the existing path variable, specifically for the command prompt session.&nbsp; Therefore, it may be a bit awkward if we want to call an executable file from Windows Explorer, as a batch file may need to be created.<br><br><b>OpenMP Note</b>: for sezero&#39;s MinGW build, you may need to unpack pthreads-w64.zip into the root of your MinGW folder (C:\MinGW_64bit) so that required OpenMP run-time libraries are available in a proper place.<br><br><b>Tips</b>: some error messages from Windows may not show up in Eclipse when we run or debug our programs within Eclipse environment.&nbsp; Try using a command prompt (cmd.exe) and you may see more informative error messages.<br><h3>Optional: Using MSYS to check if the compiled application is 64-bit</h3>There are at least two ways to check if an application is 64-bit or 32-bit.&nbsp; The easiest way is to run it and see its process name in the Windows Task Manager.&nbsp; If the process name has a suffix *32, it is 32-bit.&nbsp; If there is no such suffix, it is 64-bit.&nbsp; There is another way.&nbsp; It is less convenient in my opinion, but you can probably use it to check your application programmatically without running it at all.&nbsp; This is possible if you use MSYS as discussed below.<br><br><ol><li>Copy the executable file to a place where MSYS environment can reach.&nbsp; This is probably your home folder in C:\msys.<br><br></li><li>Enter &#39;file my_executable.exe&#39;.&nbsp; For MSYS 1.0.11 32 bits (I ran it on 64-bit Windows 7), a 64-bit executable will get a message &#39;my_executable.exe: PE executable for MS Windows&#39;.&nbsp; There is nothing about 32-bit or 64-bit tags showing up.&nbsp; A 32-bit executable, however, will get a message &#39;my_executable.exe: PE executable for MS Windows (console) Intel 80386 32-bit&#39;.&nbsp; Namely, a 32-bit executable gets a clear description about its platform, while a 64-bit executable does not get any definite description.&nbsp; This is analogous to what the Task Manager does.<br><br>For more recent version of MSYS, the file command gives PE32 for a 32-bit executable and PE32+ for a 64-bit executable.<br></li></ol><br><br>Pinyo Taeprasartsit<br>(May, Dec 2010)<br><br>This document can be viewed at <a href="http://pinyotae.blogspot.com/2010/05/eclipse-mingw-x64.html" id="q4v2" title="my blog">my blog</a> and <a href="http://docs.google.com/View?id=dggq8h5d_494hnb5n5qk" id="hqf6" title="my Google docs">my Google docs</a>.&nbsp; I welcome questions, comments, and suggestions.&nbsp; Please leave a message in <a href="http://pinyotae.blogspot.com/2010/05/eclipse-mingw-x64.html" id="navu" title="my blog">my blog</a> if you have any.&nbsp; Thank you.<br><br><br><br><br><br><br>pinyotaehttp://www.blogger.com/profile/08056348551542825367noreply@blogger.com12tag:blogger.com,1999:blog-7454278.post-9700026120353231242010-02-06T19:12:00.001-04:002010-11-11T11:48:40.241-04:00Redistributable Documents<h1>Redistributable Documents</h1><p>This web page hosts redistributable documents.&nbsp; The aim of this web page is to make things more convenient for those who want to access the document off-line or to obtain some software bundles in a convenient way.&nbsp; Documents that are not redistributable are noted and links to the official web sites are provided, instead.<br></p><h3>OpenGL 2.1 Reference Pages (Man Pages)</h3>(Feb 2010)<br>These man pages are a slightly modified version provided by the Khronos group.&nbsp; Typically, we have to SVN to get these man pages.&nbsp; The official package of the man pages, however, contain more information than what I need (most people may feel the same).&nbsp; If you want only HTML man pages, you might want to download <a href="http://docs.google.com/leaf?id=0B-WlB8Fgc324OTZiYjdiNmMtYmZkNi00Y2Q3LTk0YmEtODZiZGI1MDQ1ODQ4&amp;hl=en" id="v.9j" title="my package">my package (2MB)</a>.&nbsp; There is only one addition, index_frame.html, which is a frame version of the man page we see in <a href="http://www.opengl.org/sdk/docs/man/" id="rbt9" title="this link">this official web site</a>.&nbsp; I hope this helps those who do not want to deal with SVN and want the frame version.<br><h3>MinGW 32-bit</h3>(May 17, 2010)<br>Since MinGW installer is not finalized yet, it is awkward to get GCC 4.5.0 from the server.&nbsp; Therefore, I gathered all files that are downloaded by mingwdl.sh discussed in <a href="http://www.mingw.org/wiki/HOWTO_Install_the_MinGW_GCC_Compiler_Suite" id="s:mk" title="MinGW web site">MinGW web site</a> and made <a href="http://docs.google.com/leaf?id=0B-WlB8Fgc324Njk0NDE3ZWItMDMzZS00YjI1LWFkNzEtZmNmZTFiOGU4OWUy&amp;hl=en" id="wlil" title="a package that is ready to use">a package that is ready to use</a>.&nbsp; Just download the package if you don&#39;t need anything newer than the April-16-2010 release (GCC 4.5.0).&nbsp; With the package, there is no need to bother with wget or bash.<br><br><br>Pinyo Taeprasartsit<br><br>(This document can be viewed at <a href="http://pinyotae.blogspot.com/2010/02/redistributable-documents.html" id="tg41" title="my blog">my blog</a> and my <a href="http://docs.google.com/View?id=dggq8h5d_475fs9t7rfv" id="o7id" title="Google docs">Google docs</a>)<br><br><br><br><br><br>pinyotaehttp://www.blogger.com/profile/08056348551542825367noreply@blogger.com0tag:blogger.com,1999:blog-7454278.post-37053892463731933882010-02-04T15:30:00.001-04:002010-03-21T03:34:58.650-04:00Dealing with Build Errors in Visual C++ Project<h1>Dealing with Build Errors in Visual C++ Project</h1><h3><b>Warning C4251 for vector type in DLL build</b></h3>When we build a shared library, it is possible that container specialization type is not available outside the scope of the shared library, as the caller may not know such type.<br>This, however, generates only warning for an STL container.&nbsp; We can deal with this warning by explicit declaration of the library interface.<br><br>For example: <font face="courier new">template class DLL_IMEXPORT_DEF std::vector&lt;int&gt;;</font><br><br>Unfortunately, there may be another warning if the type in the STL container is a class or a pointer to an object, not a primitive type.<br>For example: <font face="courier new">template class DLL_IMEXPORT_DEF std::vector&lt;XmlNode&gt;;</font><br>causes a warning about std::allocator&lt;_Ty,_Alloc&gt;.<br><br>This problem can be solved (sort of, see the note below) by adding a dll interface of the problematic allocator in front of the export of the intended STL container.<br>That is, we have to write (order of declaration is important).<br><font face="courier new">template class XML_MANAGER_IMEXPORT std::allocator&lt;XmlNode&gt;;</font><br style="font-family:Courier New"><font face="courier new">template class XML_MANAGER_IMEXPORT std::vector&lt;XmlNode&gt;;</font><br>to be free of the warning.<br><br>A vector of CString has some special requirements for its DLL interface.&nbsp; I need to have additional interface declaration, as shown below.<br><font face="courier new">template class XML_MANAGER_IMEXPORT std::allocator&lt;CString&gt;;</font><br style="font-family:Courier New"><i><font size="2"><b><font face="courier new">template class XML_MANAGER_IMEXPORT std::_Container_base_aux_alloc_real&lt; std::allocator&lt;CString&gt; &gt;;</font></b></font></i><br style="font-family:Courier New"><font face="courier new">template class XML_MANAGER_IMEXPORT std::vector&lt;CString&gt;;</font><br style="font-family:Courier New"><br><br>Note: exporting STL template specialized class may cause link error with multiply defined class.&nbsp; Microsoft discusses about a way to deal with STL export <a href="http://support.microsoft.com/kb/q168958/" id="v3cf" title="in this link">in this link</a><br><br>More info is available at:<br>http://www.unknownroad.com/rtfm/VisualStudio/warningC4251.html<br><br><h3><b>Polymorphism with Boost shared_ptr</b></h3>Using a shared_ptr is a great way to avoid almost all kinds of memory leak.&nbsp; Moreover, we have no need to find out the last owner of an object.&nbsp; Therefore, complexity in programming logic is reduced.&nbsp; Unfortunately, it is not straightforward to employ polymorphism with a shared_ptr, as we cannot just cast the pointer in a typical C++ fashion, e.g. dynamic_cast.&nbsp; Thus, Boost library comes with a special way to cast its smart pointers.<br><br><font face="Courier New">boost::shared_ptr&lt;T_A&gt; testPtr(new </font><font face="Courier New">T_A</font><font face="Courier New">(blah));<br><br> boost::shared_ptr&lt;T_B&gt; anotherTestPtr = boost::dynamic_pointer_cast&lt;</font><font face="Courier New">T_B</font><font face="Courier New">&gt;(</font><font face="Courier New">testPtr</font><font face="Courier New">));<br></font><br>That is &#39;<font face="Courier New">boost::dynamic_pointer_cast&#39; </font>is a way to solve this issue.<br><br>More info can be found <a href="http://codeblog.bsdninjas.co.uk/index.php?/archives/118-Using-polymorphism-with-boostshared_ptr.html">here</a> and <a href="http://www.boost.org/doc/libs/1_39_0/libs/smart_ptr/pointer_cast.html">there</a>.<br><br>====================<br><br>If you deal with the polymorphism in a vector.&nbsp; For example, we want to have std::vector&lt; boost::shared_ptr&lt;T_Base&gt; &gt; to hold shared_ptr of T_Child1 and T_Child2.&nbsp; In this example, we can do it as follows.<br><br><font face="courier new">std::vector&lt; boost::shared_ptr&lt;T_Base&gt; &gt; vecPoly;</font><br><font face="courier new">boost::shared_ptr&lt;T_Base&gt; childPtr1( new T_Child1() );</font><br><font face="courier new">boost::shared_ptr&lt;T_Base&gt; childPtr2( new T_Child2() );<br><br style="font-family:Courier New"></font><font face="courier new">vecPoly.push_back( </font><font face="courier new">childPtr1</font><font face="courier new"> );</font><br><font face="courier new">vecPoly</font><font face="courier new">.push_back( </font><font face="courier new">childPtr2</font><font face="courier new"> );</font><br style="font-family:Courier New"><br>There is nothing to worry about calling virtual functions.&nbsp; They will be called properly as usual.<br><br><h3>Definition of a template class in a DLL cannot be found</h3>If a template class is not employed within the DLL itself, its actual binary may not be created at a compile time or link time.<br>Also, if we inline everything in the template class and use the class inside the DLL, its actual binary may not be created and accessible by other DLLs or applications.<br>We can deal with the problem by specialization of the template class and avoiding inlining constructors and destructors of the class.&nbsp; Performances may decrease, but it solves the problem.<br><br>Error with afximpl.h<br><br>When a project incude afximpl.h (typically in stdafx.h), compile errors may show up in Visual Studio 2008 (Visual C++ 9.0).&nbsp; The error message looks like:<br>1&gt;c:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\include\..\atlmfc\src\mfc\afximpl.h(635) : error C2059: syntax error : &#39;&lt;L_TYPE_raw&gt;&#39;<br>1&gt;c:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\include\..\atlmfc\src\mfc\afximpl.h(635) : error C2238: unexpected token(s) preceding &#39;;&#39;<br><br>It seems that Microsoft did not purge this error yet, but there is a workaround that is effective.<br><br>&quot;place the following line in your code before including afximpl.h:<br>DECLARE_HANDLE(HRAWINPUT); &quot;<br><br>Reference: http://connect.microsoft.com/VisualStudio/feedback/details/276404/windows-2000-settings-incompatible-with-afximpl-h#details<br><br><h3 style="font-family:Arial Black"><span class="pln">error LNK2005</span><span class="pun">:</span> <span class="str">&quot;void * __cdecl operator new(unsigned int)&quot;</span> <span class="pun">(??</span><span class="lit">2@YAPAXI@Z</span><span class="pun">)</span><span class="pln"> already </span><span class="kwd">defined</span> <span class="kwd">in</span><span class="pln"> ...</span></h3>Cause:<br>&quot;The CRT libraries use weak external linkage for the <b>new</b>, <b>delete</b>, and <b>DllMain</b> functions. The MFC libraries also contain <b>new</b>, <b>delete</b>, and <b>DllMain</b> functions. These functions require the MFC libraries to be linked before the CRT library is linked.&quot; [<a href="http://support.microsoft.com/kb/148652" id="q1wj" title="Reference">Reference</a>]<br><br>This can be fixed by forcing the order of library linking.&nbsp; This is shown in the above reference and directly quoted here:<br><br>&quot;Visual C++ does not contain this header file. To create this file, follow these steps: <ol><li>Open Msdev\Mfc\Include\Afx.h. </li><li>Select the lines between #ifndef _AFX_NOFORCE_LIBS and #endif //!_AFX_NOFORCE_LIBS. </li><li>Copy the selection to the Windows Clipboard. </li><li>Create a new text file. </li><li>Paste the contents of the Clipboard into this new file. </li><li>Save the file as Msdev\Mfc\Include\Forcelib.h.&quot;</li></ol><br><h3>Separate inline function declaration and definition</h3>In Visucal C++, separating an inline function declaration and definition across header and source files is not possible, unless the inline function is virtual.&nbsp; However, we can separate declaration and definition in the same header file.&nbsp; The only difference is that we should add a keyword inline in front of the definition.&nbsp; Example:<br><br><p>&quot;When you declare an inline member function, it looks just like a normal member function: </p><div class="CodeBlock"> &nbsp;class Fred {<br> &nbsp;public:<br> &nbsp;&nbsp;&nbsp;void f(int i, char c);<br> &nbsp;}; </div><p>But when you define an inline member function, you prepend the member function&#39;s definition with the keyword inline, and you put the definition into a header file: </p><div class="CodeBlock"> &nbsp;inline<br> &nbsp;void Fred::f(int i, char c)<br> &nbsp;{<br> &nbsp;&nbsp;&nbsp;<i>...</i><br> &nbsp;} </div><p>It&#39;s usually imperative that the function&#39;s definition (the part between the {...}) be placed in a header file. If you put the inline function&#39;s definition into a .cpp file, and if it is called from some other .cpp file, you&#39;ll get an &quot;unresolved external&quot; error from the linker.&quot;&nbsp; [<a href="http://www.parashift.com/c++-faq-lite/inline-functions.html" id="xgv9" title="This is quoted from another web site">This is quoted from another web site</a>.] </p><br><br><br>------------------------------------<br>Pinyo Taeprasartsit<br><br>(This document can be viewed at <a href="http://pinyotae.blogspot.com/2010/02/dealing-with-build-errors-in-visual-c.html" id="t4q." title="my blog">my blog</a> and <a href="http://docs.google.com/View?id=dggq8h5d_473dv23b7c4" id="i9ny" title="Google docs">Google docs</a>)<br><br><br>pinyotaehttp://www.blogger.com/profile/08056348551542825367noreply@blogger.com0tag:blogger.com,1999:blog-7454278.post-63578868905057079622010-02-04T14:59:00.001-04:002010-11-10T13:38:07.957-04:00Building and Debugging Tips in Visual C++<h1>Building and Debugging Tips in Visual C++</h1>(Jan 2010-Present)<br><div>This document compile my ongoing experience with Visual C++.&nbsp; There are many more tips I know, but they are related to generic C++.&nbsp; I&#39;m thinking about creating a separate document for them or just put them here.<br><br><h3>Can we debug a DLL project?&nbsp; Why can we set a DLL project as a startup project, even though it is not executable per se?</h3>Yes, we can debug a DLL project.&nbsp; Plus, it does make sense to make it a startup project.&nbsp; In fact, setting it as a startup project is a way to debug the DLL project, provided that we have any executable file to call the DLL.<br><br>Complete info is a available in <a href="http://msdn.microsoft.com/en-us/library/605a12zt.aspx" id="mspa" title="this link">this link</a>.&nbsp; Here, I quoted the essential information for Visual C++.<br><h4 class="procedureSubHeading">&quot;</h4><h4 class="procedureSubHeading">To specify the calling application in a C++ project</h4><div class="subSection"><ol><li><p>In <span class="label">Solution Explorer</span>, select the DLL project.</p></li><li><p>On the <span class="label">View</span> menu, choose <span class="label">Property Pages</span>.</p></li><li><p>In the <span class="parameter">Project</span><span class="label"> Property Pages</span> window, in the <span class="label">Configuration</span> drop-down list, choose <span class="label">Debug</span>.</p></li><li><p>Open the <span class="label">Configuration Properties</span> folder, and select the <span class="label">Debugging</span> category.</p></li><li><p>In the <span class="label">Debugger to launch</span> list, choose <span class="label">Local Windows Debugger</span> or <span class="label">Remote Windows Debugger</span>.</p></li><li><p>In the <span class="label">Command</span> or <span class="label">Remote Command</span> box, click the drop-down arrow, and select <span class="label">Browse</span> from the list to locate the application. Alternatively, type the path and name of the application.</p></li><li><p>Type any necessary program arguments in the <span class="label">Command Arguments</span> box.</p></li></ol><b>&quot;</b><br></div><br><h3>What if a break point cannot be hit because &#39;no symbol has been loaded for this document&#39;.</h3>In Visual C++, this seems to be a common problem.&nbsp; First of all, we have to check if we have debugging symbols loaded or not.&nbsp; Go to the &#39;Output&#39; window (this is typically one of the tabs at the bottom of your VC++ window).&nbsp;&nbsp; Then, look for a line telling about loading DLL.&nbsp; For example,&nbsp; there should be a line like this<br><br>&#39;TesterConsole.exe&#39;: Loaded &#39;F:\Work\A.dll&#39;, [IMPORTANT MESSAGE HERE]<br><br>Next, check what your IMPORTANT MESSAGE HERE is.&nbsp;&nbsp; If it is &#39;Binary was not built with debug information&#39;, we have to check a few points in our project properties.&nbsp; Go to the project properties.&nbsp; In the tab &#39;Configuration Properties -&gt; C/C++ -&gt; General&#39;, it is best that &#39;Debug Information Format&#39; is a good one, which is &#39;Program Database (/Zi)&#39; and &#39;Program Database for Edit &amp; Continue (/ZI)&#39;.&nbsp; Then, go to a neigboring tab &#39;Optimization&#39;, it is highly recommended to set &#39;Optimization&#39; to &#39;Disabled (/Od)&#39;.<br><br>The final step is check your linker option.&nbsp; Go to the tab &#39;Configuration Properties -&gt; Linker -&gt; Debugging&#39;.&nbsp; Next, set &#39;Generate Debug Info&#39; to &#39;Yes (/DEBUG)&#39;.<br>(Some additional information is in <u><a href="http://social.msdn.microsoft.com/forums/en-US/Vsexpressinstall/thread/40d703d5-79cc-463d-8964-34d086fe57f5/" id="um-m" title="this link">this link</a></u>.)<br><br>If your IMPORTANT MESSAGE HERE is NOT about &#39;Binary was not built with debug information&#39;, chances are your debugging information is not synchronized with your DLL or your PDB (program data base) file is corrupt.&nbsp; Try cleaning and rebuilding the affected DLL project.<br><br><h3>Stand Between Debug and Release Modes</h3>In some cases, it is too time consuming to debug a program in the Debug mode for a computationally intensive application, especially if we only want to see a crash site and call stack.&nbsp; In such cases, we can choose to create another configuration.&nbsp; Let&#39;s call the configuration &#39;Release w Assertion Enabled&#39;.&nbsp; This is actually a release mode without a preprocessor symbol NDEBUG.&nbsp; Without NDEBUG, all assertion mechanisms are performed like in a debug mode, but the code is optimized.&nbsp; If your program crashes, you can see the crash site and call stack, even though you cannot see accurate values of variables.&nbsp; This is significantly useful when we need to get some idea about the problem.&nbsp; <br><br>At this point, you might ask, &#39;Why do we need another configuration?&#39; and &#39;Why don&#39;t we just remove NDEBUG during debugging process and insert it back when debugging is done?&#39;&nbsp; The answer is if we change any preprocessor symbol, the compiler must re-compile everything.&nbsp; This is very time consuming if your project is large.&nbsp; Moreover, in most cases, the debugging process never ends.&nbsp; We have to go back and forth between release and debug builds all the time.&nbsp; Creating a separate build, therefore, is a better way for a large and computationally intensive project in the long run.<br><br>Playing around with Visual C++, I found that Visual C++ might behave strangely if I modify a debug mode by just removing the preprocessor symbol _DEBUG and letting the executable call another library built in a release mode.&nbsp; In the scenario, the run-time check might find that the heap or stack around a variable from the library is corrupted, but there is actually nothing wrong. <br><br><h3><b>String Conversion</b></h3>String conversion is usually necessary when we work with XML data, as XML uses Unicode character set by default.&nbsp; Most parts of our work, however, may mainly use the ANSI character set.&nbsp; This typically requires us to employ CA2W to convert an ANSI text to a Unicode text.&nbsp; The usage of CA2W, however, may be quite unnatural to most of us.<br><br>For example, the use <font face="courier new">LPCWSTR szr = CA2W(szReplaceFile);</font> is actually invalid because LPCTSTR becomes a pointer to a temporary string created during a conversion.&nbsp; Therefore, it will be scrapped immediately after CA2W returns.&nbsp; The correct use is <font face="Courier New">CA2W szr(szReplaceFile);<font face="verdana">.</font><font face="verdana">&nbsp; Look strange, right?&nbsp; No doubt, a macro is usually strange.</font><br><br></font><h3>Assertion Failed at the line ASSERT(AfxGetThread() == NULL)</h3>This assertion is at the line 380 in appcore.cpp of Visual C++ 2008--version 9.0.&nbsp; (Note that other versions may have this assertion at different lines.)&nbsp; This issue arises if there are multiple MFC-application threads running at the same time (to be more specific, they are generated by CWinApp objects).&nbsp; It is usually caused by calling MFC DLLs that comes with their own &#39;theApp&#39;, an object derived from CWinApp.&nbsp; When these DLLs are initialized, they may start their own MFC-application threads, while we expect to have only one MFC-application thread--the one from our executable project.&nbsp; <br><br>There is a discussion about this issue in <a href="http://www.pcreview.co.uk/forums/thread-2277687.php" id="mu5_" title="this link">this link</a>.&nbsp; Unfortunately, it does not tell us much about any practical approach for a solution. Thus, we have to figure this out ourselves.&nbsp; If your application involves many DLLs, you probably have no idea what DLLs are culprits.&nbsp; After trying for hours, I finally come up with a systematic method to identify the problematic DLLs and, of course, I have a solution for this problem.<br><br>To begin, set a break point at the assertion line <font face="courier new">ASSERT(AfxGetThread() == NULL)</font>.&nbsp; Then, start the debugger.&nbsp; At the break point, check &#39;Call Stack&#39;. &nbsp;(Those who are not familiar with debugging and the call stack might want to see <a href="http://msdn.microsoft.com/en-us/library/a3694ts5.aspx" id="wtps" title="this reference">this reference</a>.) &nbsp;If the call stack involves a DLL that is not mfcXXd.dll, such a DLL is likely to be a culprit, especially if it uses MFC in a shared library.&nbsp;&nbsp;</div><br><div>Next, check the source code of the library and look for the file with &#39;theApp&#39; in the suspect library.&nbsp; Then, check its InitInstance() function.&nbsp; If you find no <font face="courier new">AFX_MANAGE_STATE(AfxGetStaticModuleState( ));</font> at the beginning of <font face="courier new">InitInstance()</font>, insert it at the very beginning of the function.&nbsp; Then, continue this process until every involved CWinApp DLL is properly equipped with <font face="courier new">AFX_MANAGE_STATE(AfxGetStaticModuleState( ))</font>.&nbsp;&nbsp;</div><br><div>If the AFX_MANAGE_STATE causes linker errors, you might have an invalid preprocessor symbol.&nbsp; The CWinApp DLL is usually configured with _USRDLL, not _LIB, because it is a dynamically linked library.&nbsp; You may find that changing _LIB to _USRDLL helps solve your linker errors.<br><br><h3>Halt at First-Chance Exceptions</h3>First-chance exceptions in Visual C++ are a kind of access violation with code c0000005.&nbsp; Many of them are not critical and we can possibly ignore them.&nbsp; However, it is better, if we can get rid all of them, as your customers may demand that no compiler/linker warnings and no such exceptions are present when you ship your product.&nbsp;&nbsp;</div><br><div>Visual C++, nonetheless, may not stop at the problematic point and just continue.&nbsp; This makes it hard to tackle the problem.&nbsp; So, we might want to force break for all exception.&nbsp; The exception sheet can be accessed from menu Debug -&gt; Exceptions (also by Ctrl-Alt-E, see Figure FCE1) in Visual Studio 2008.<br><br>If all exceptions are to be tackled, check all of the check boxes there so that all exception will be thrown (and we are forced to handle or get rid of them from the first place).&nbsp; See Figure FCE2.&nbsp; If only first chance exceptions, which are in fact a kind of access violtion, are to be handled, go to Win32 Exceptions and check Access Violation (Figure FCE3).&nbsp; <br><br>Note that there is a button on the right that can reset exception settings to default and can even add a new one to the list (Figure FCE 4).&nbsp; Adding a new one can possibly add our custom exceptions to the list, I belive (not try it myself yet).<br><br><div id="l0cn" style="text-align:center"><img src="http://docs.google.com/File?id=dggq8h5d_502cgzpr9ch_b" style="height:237px;width:301px"></div><div style="text-align:center"><b>Figure FCE1</b>.&nbsp; Exeption setting menu<br><br><div id="y7l6" style="text-align:center"><img src="http://docs.google.com/File?id=dggq8h5d_503c89cz2gb_b" style="height:197px;width:560px"><br><b>Figure FCE2</b>.&nbsp; Set to throw all exceptions known by Visual C++.<br><br><div id="sg2t" style="text-align:center"><img src="http://docs.google.com/File?id=dggq8h5d_504f535m6g2_b" style="height:155px;width:517px"></div><b>Figure FCE3</b>. Focus on first-chance exception.&nbsp; However, it is recommended to (finally) handle all kinds of exceptions that come into your way.<br><br><div id="i9.s" style="text-align:center"><img src="http://docs.google.com/File?id=dggq8h5d_5055kv4xdhw_b" style="height:153px;width:143px"></div><b>Figure FCE4</b>.&nbsp; Remember that we can reset the settings or add a new exception to the list.<br></div><br><div style="text-align:left">Acknowledgement: <a href="http://peterkellner.net/2007/08/10/stoponexceptionvs/" id="v8wq" title="Peter Kellner">Peter Kellner</a><br></div></div><br><h3>Program Exits with Code 0, but Unexpectedly</h3>Typically, a program exiting with code 0 means there is nothing wrong.&nbsp; However, sometimes a program exits in this way unexpectedly.&nbsp; Also, nothing shows up at all.&nbsp; I encountered this problem when I tried to build a program that uses a statically linked library.&nbsp; That library, nonetheless, was created as a dynamically linked library before.&nbsp; Therefore, there is a variable theApp inside its main file.<br><br>In general, this does not cause any problem and we can switch between dynamic-lib and static-lib configurations any time we want.&nbsp; Nevertheless, there is one thing we need to be careful.&nbsp; In a static-lib configuration, we are not supposed to let the program execution see theApp.&nbsp; Why?&nbsp; Because theApp will be initialized and start an instance of an MFC application thread.&nbsp; Subsequently, theApp just exits with code 0.&nbsp; This problem arises if we add something to the library main file and that file is in a part of compilation/execution.<br><br>To check if that is the actual cause of the problem, set a break point at the beginning of InitInstance() in a suspect library.&nbsp; If the function is called, theApp is initialized in a wrong way.&nbsp; Therefore, we need to find a way to prevent theApp to get involved.&nbsp; This can be done by removing things that you add to the library main file.&nbsp; If that means a lot of work, try using the macro to exclude theApp.&nbsp; <br><br>For example:<br><font face="courier new">#ifdef _NO_THEAPP</font><br style="font-family:Courier New"><font face="courier new">CLibApp theApp;</font><br style="font-family:Courier New"><font face="courier new">#endif</font><br><br>The above lines of code should effectively deal with the problem, provided that _NO_THEAPP is defined properly (as a preprocessor, for example).<br><br><br>Pinyo Taeprasartsit<br><br>(This document is viewable at <a href="http://pinyotae.blogspot.com/2010/02/building-and-debugging-tips-in-visual-c.html" id="dow8" title="pinyotae.blogspot.com">pinyotae.blogspot.com</a> and <a href="http://docs.google.com/View?id=dggq8h5d_471g5cs9jcf" id="kzjq" title="docs.google.com">docs.google.com</a>)<br></div><br>pinyotaehttp://www.blogger.com/profile/08056348551542825367noreply@blogger.com5tag:blogger.com,1999:blog-7454278.post-45708816524417691462010-01-14T21:01:00.001-04:002010-01-14T21:01:32.085-04:00The Way of DLL and Lib<div>(Jan 14, 2010)<br><h3><b>Why do we need both .lib and .dll at the same time?</b></h3>Today, I helped my friends figure some build and run-time problems in Visual Studio 2008.&nbsp; I'm not familiar with these problems at all, but I can draw some important conclusions that I earlier did not realized.&nbsp; It is about the usage of lib and DLL with and without source code of the library.&nbsp; Earlier, I created several projects and made them static libraries.&nbsp; Then, a few executable projects utilized them inside the same solution tree within Visual Studio 2008 development environment.&nbsp; These executable projects can be run without the presence of DLL at all.<br><br>However, when I worked with freeglut.lib, a tool kit for OpenGL, I needed freeglut.dll during run-time, even though I planned to statically linked my project with freeglut.lib.&nbsp; This is opposite to what I expected, but understandable.&nbsp; If we do not have source code in the same solution tree, the compiler/linker does not have enough information about what should be incorporated into an executable file.&nbsp; Therefore, only .lib stub/proxy is employed during linking and actual implementation is found during run-time. <br><br><br>Another question is "So, why can't we have only .dll and throw away all .lib files when we are going to use the .dll via dynamic linking?"<br><br></div><div>A few reasons are elaborated at <a title="'stackoverflow' website" href="http://stackoverflow.com/questions/1297013/why-do-we-still-need-a-lib-stub-file-when-weve-got-the-actual-dll-implementati" id="bihx">'stackoverflow' website</a>.&nbsp; The strongest reason may be '.lib manifest files allow us to work with different versions of DLLs in our system' and 'Native DLL's do not have strong names, so it may be possible to pick up the wrong version of the DLL'.&nbsp; However, it seems possible to link with only DLL by using some other work (shown in the same page of stackoverflow).&nbsp; The limitation of stand-alone DLL probably comes from an old design of compiler/linker/operating system (run-time platform), as it is pointed out that MS .Net can do this.<br></div><div><br></div><br>pinyotaehttp://www.blogger.com/profile/08056348551542825367noreply@blogger.com2tag:blogger.com,1999:blog-7454278.post-53431397546891442092010-01-12T17:25:00.001-04:002010-02-05T20:24:18.058-04:00C++ Template in Shared Library/DLL(Jan 12, 2010)<br><br /><br><br />Using a C++ template in a shared library or DLL across the library boundary is not permitted, as all class and method definition must be available at the compile time if a template class or method is to be exported.&nbsp; Therefore, the template class/method must be exclusively utilized within the shared library/DLL and should not declared AFX_EXT_CLASS or __declspec( dllexport ) for Visual C++.<br><br /><br>For your information, Macro AFX_EXT_CLASS does not have the same meaning all the time.&nbsp; In fact, it depends on preprocessor symbols.&nbsp; From MSDN, it is stated that<br><br /><br><br />"This macro is defined by MFC as <b>__declspec(dllexport)</b> when the preprocessor symbols <b>_AFXDLL</b> and <b>_AFXEXT</b> are defined. But the macro is defined as <b>__declspec(dllimport)</b> when <b>_AFXDLL</b> is defined and <b>_AFXEXT</b> is not defined. When defined, the preprocessor symbol <b>_AFXDLL</b> indicates that the shared version of MFC is being used by the target executable (either a DLL or an application). When both <b>_AFXDLL</b> and <b>_AFXEXT</b> are defined, this indicates that the target executable is an extension DLL."<br><br /><br><br />This may be a good idea to have one header that can work as both dllexport and dllimport, depending on usage.&nbsp; However, this may cause confusion to a new comer until he or she realizes how AFX_EXT_CLASS works.&nbsp; Moreover, I still wonder what will happen if a DLL uses another DLL because header files from both DLLs have AFX_EXT_CLASS, but it has different meaning due to dual contexts.&nbsp; <br><br>Microsoft discusses this in their own web site: http://support.microsoft.com/kb/128199.&nbsp; In short, this is a limitation for the use of AFX_EXT_CLASS.&nbsp; The issue in the above example can be solved by using a directive for each library.&nbsp; For example, suppose there are two DLLs: abc.dll and def.dll.&nbsp; Header files for abc.dll has a directive #define ABC_DLL_IMEXPORT __declspec(dllexport) or __declspec(dllimport), depending on usage context, while header files for def.dll has #define DEF_DLL_IMEXPORT __declspec(dllexport) or __declspec(dllimport).&nbsp; <br>pinyotaehttp://www.blogger.com/profile/08056348551542825367noreply@blogger.com0tag:blogger.com,1999:blog-7454278.post-42242241035143666302009-12-14T04:13:00.001-04:002009-12-14T04:13:29.617-04:00RIP DVD or create ISO image of DVD in Linux(Dec 13, 2009)<br><br><div style="text-align: left;">I tried to rip a DVD in Linux.&nbsp; Mostly, I followed the instructions available at <a title="instructables.com" href="http://www.instructables.com/id/How-To-Rip-A-DVD-Linux/" id="kcgx">instructables.com</a>.&nbsp; There are notes I want to jot down here.<br><ol><li>We need dvd::rip, as instructed in the website.&nbsp; Do not, however, bother with the dvd::rip's website.&nbsp; Just grab it directly from Ubuntu's Synaptic package manager.&nbsp; This is the easiest way to do.<br><br></li><li>We probably still need mplayer and rar.&nbsp; Get them from Synaptic again.<br><br></li><li>At this point, we are ready to rip a DVD, as shown at instructables.com.<br><br></li><li>If you want to transcode the vob files from dvd::rip, try using vlc.<br></li></ol><br><br></div>If you want to create an ISO image of your DVD, using k3b or GnomeBaker is a way to go.<br>pinyotaehttp://www.blogger.com/profile/08056348551542825367noreply@blogger.com0tag:blogger.com,1999:blog-7454278.post-52169325704992058772009-11-13T04:33:00.001-04:002010-02-08T14:03:49.883-04:00Fix Ubuntu ATI driver problem caused by kernel upgrade(Nov 13, 2009)<br><br>Updating kernel can cause some headache to Ubuntu users who use a proprietary video driver.&nbsp; In my case, I used ATI's driver and upgraded kernel from 2.6.26 to 2.6.28.&nbsp; Once kernel upgrade was complete, a display screen became garbage.&nbsp; The best way to solve this issue is probably purging the old driver and reinstall it from scratch.<br><br>The procedure is well described <a title="here" href="https://wiki.ubuntu.com/X/Troubleshooting/FglrxInteferesWithRadeonDriver" id="z5o7">here</a>.&nbsp; I followed the procedure in Section 'Need to fully remove -fglrx and reinstall -ati from scratch'.&nbsp; Note that when we have the driver problem, we cannot access X server and need to boot the Ubuntu into a recover mode to maintain the system.<br><br>If the process is successful, we will be able to boot to the X server again.&nbsp; However, the proprietary ATI driver may not be fully reinstalled as we expect.&nbsp; There is no critical problem here.&nbsp; Just download and reinstall it again from its script.<br><br><br><p class="line867"></p><font face="Courier New"> sudo /usr/share/ati/fglrx-uninstall.sh # (if it exists)<br> sudo apt-get remove --purge fglrx*<br> sudo apt-get remove --purge xserver-xorg-video-ati xserver-xorg-video-radeon <br> sudo apt-get install xserver-xorg-video-ati<br> sudo apt-get install --reinstall libgl1-mesa-glx libgl1-mesa-dri xserver-xorg-core<br> sudo dpkg-reconfigure xserver-xorg</font><br><br>Pinyo Taeprasartsit<br>pinyotaehttp://www.blogger.com/profile/08056348551542825367noreply@blogger.com0tag:blogger.com,1999:blog-7454278.post-16715015701695476872009-09-19T13:46:00.001-04:002010-06-12T14:17:15.798-04:00GL_POINTS + Qt<h1>GL_POINTS + Qt</h1>There are a few ways to do 2D OpenGL: GL_POINTS, glDrawPixels/glPixelZoom, and 2D texture.<br><br>The strength of GL_POINTS is its simplicity, while its weakness is inability to scale in a way most people intend.<br>Basically, each point occupied exactly one pixel of the screen.&nbsp; If a window size increase, the point is still drawn as a single pixel.<br>Therefore, some pixels in a window become background color.<br><br>Consequently, GL_POINTS can be a strong candidate for 2D graphics if the window will not be resized.<br><br>The following function shows the a call list function, as an example.<br><font size="1"><br style="font-family:Courier New"><font size="2"><font face="courier new">/// This example draw a red horizontal line made of individual points at</font><br style="font-family:Courier New"><font face="courier new">///&nbsp;&nbsp; the very middle of its window.</font><br style="font-family:Courier New"><font face="courier new">GLuint GLPoint::makeCallList() {</font><br style="font-family:Courier New"><font face="courier new">&nbsp;&nbsp; &nbsp;glClear(GL_COLOR_BUFFER_BIT);</font><br style="font-family:Courier New"><br style="font-family:Courier New"><font face="courier new">&nbsp;&nbsp;&nbsp; GLuint list = glGenLists(1);</font><br style="font-family:Courier New"><font face="courier new">&nbsp;&nbsp;&nbsp; glNewList(list, GL_COMPILE);</font><br style="font-family:Courier New"><br style="font-family:Courier New"><font face="courier new">&nbsp;&nbsp;&nbsp; glColor3f(1.0f, 0.25f, 0.25f);</font><br style="font-family:Courier New"><font face="courier new">&nbsp;&nbsp;&nbsp; glBegin(GL_POINTS);</font><br style="font-family:Courier New"><font face="courier new">&nbsp;&nbsp;&nbsp; {</font><br style="font-family:Courier New"><font face="courier new">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;int nRow = m_nHeight / 2;</font><br style="font-family:Courier New"><font face="courier new">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;for (int i = 0; i &lt; m_nWidth; ++i)</font><br style="font-family:Courier New"><font face="courier new">&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;glVertex2s(i, nRow);</font><br style="font-family:Courier New"><font face="courier new">&nbsp;&nbsp;&nbsp; }</font><br style="font-family:Courier New"><font face="courier new">&nbsp;&nbsp;&nbsp; glEnd();</font><br style="font-family:Courier New"><br style="font-family:Courier New"><font face="courier new">&nbsp;&nbsp;&nbsp; glEndList();</font><br style="font-family:Courier New"><br style="font-family:Courier New"><font face="courier new">&nbsp;&nbsp;&nbsp; return list;</font><br style="font-family:Courier New"><font face="courier new">}</font></font></font><br><br>Since we are doing 2D graphics, it is recommended to disable depth test, as shown in the following initialized function.<br><br><font size="2"><font face="courier new">void GLPoint::initializeGL()</font><br style="font-family:Courier New"><font face="courier new">{</font><br style="font-family:Courier New"><font face="courier new">&nbsp;&nbsp; &nbsp;glClearColor(0.0, 0.0, 0.0, 0.0);</font><br style="font-family:Courier New"><font face="courier new">&nbsp;&nbsp; &nbsp;glDisable(GL_DEPTH_TEST);&nbsp;&nbsp; &nbsp;// we are going to do 2D OpenGL</font><br style="font-family:Courier New"><font face="courier new">&nbsp;&nbsp; &nbsp;glClear(GL_COLOR_BUFFER_BIT);</font><br style="font-family:Courier New"><br style="font-family:Courier New"><font face="courier new">&nbsp;&nbsp; &nbsp;glMatrixMode(GL_PROJECTION);</font><br style="font-family:Courier New"><font face="courier new">&nbsp;&nbsp; &nbsp;glLoadIdentity();</font><br style="font-family:Courier New"><font face="courier new">&nbsp;&nbsp; &nbsp;glOrtho(0, m_nWidth, 0, m_nHeight, 0, 1);</font><br style="font-family:Courier New"><font face="courier new">&nbsp;&nbsp; &nbsp;glMatrixMode(GL_MODELVIEW);</font><br style="font-family:Courier New"><br style="font-family:Courier New"><font face="courier new">&nbsp;&nbsp;&nbsp; callList = makeCallList();</font><br style="font-family:Courier New"><font face="courier new">}</font><br></font><br>An example Eclipse CDT / Qt project is stored at <a href="http://cid-a4f67aec001a7049.skydrive.live.com/self.aspx/plaza/OpenGL/GLPoint.zip" id="r0dm" title="a public folder here">a public folder here</a>.<br>The project file is valid for Eclipse CDT on Linux with Qt integration (Ubuntu 9.04 Juanty), but the main part should be applicable to most C++ environment.<br><br>Pinyo Taeprasartsit<br>August-September 2009<br>pinyotaehttp://www.blogger.com/profile/08056348551542825367noreply@blogger.com1tag:blogger.com,1999:blog-7454278.post-66482650087636810272009-07-02T15:05:00.001-04:002009-07-18T19:02:21.676-04:00เรื่องของนักเรียนทุน(เรื่องนี้ผมเขียนตอบข้อความของเพื่อนที่ http://wizardme.spaces.live.com/blog/cns!59943C23FC60FF0B!1962.entry?wa=wsignin1.0&amp;sa=780937976<br>เนื่องจากว่ามันยาวมาก และหวังว่าจะมีประโยชน์ต่อคนอื่นด้วย จึงนำมาเก็บไว้ในที่ส่วนตัว)<br><br>นี่ อย่าต่อว่าทาง สนร เกินกว่าเหตุสิ อย่าลืมว่าเรามาจากประเทศไทย เราก็เป็นเหมือนลูกคนจน จะทำอะไรตามใจชอบมากก็ไม่ได้<br>ก็เราบอกเองไม่ใช่เหรอว่าเรามจากครอบครัวคนจน เราก็น่าจะเข้าใจข้อจำกัดพวกนี้ดี<br><br>เราไม่ควรจะมัวแต่ไปมองพวกคนในฟากรัฐบาลที่ได้เงินมากแบบไม่สมควร เพราะเรื่องเลว ๆ มันก็มีอยู่ทุกวงการ <br>เป็นต้นว่าในสายทางเอกชน พวกผู้บริหารสถาบันการเงินก็อาจจะได้รายได้มากอย่างไร้ความละอายใจ<br><br>พูดง่าย ๆ ก็คือ การเปลี่ยนแปลงบางอย่าง ใช่ว่าจะเป็นไปได้ด้วยกำลังของ สนร แต่เพียงฝ่ายเดียว<br>อย่างเราตอนทำงานในบริษัท ก็อาจจะมีเรื่องที่เราไม่ชอบอยู่ เราก็อาจจะไม่สามารถเปลี่ยนมันได้<br><br>และถ้ามองย้อนกลับเข้ามาที่ตัว แม้แต่ตัวของเราเองก็ยังไม่อาจจะเปลี่ยนสิ่งที่เราไม่ชอบในตัวเราเองได้<br>ดังนั้นอย่าตำหนิโลกภายนอกเกินกว่าจำเป็นเลย<br><br>ส่วนทาง สนร ที่จริงโดยรวมเค้าก็ดำเนินการอย่างมีเหตุผลอยู่ ถึงจะมีอะไรที่ดูแปลก ๆ ในบางพื้นที่ แต่จะให้ถูกต้องหมดก็คงจะไม่ง่ายนัก<br>ถ้าเราเป็น สนร เอง เราก็อาจจะไม่รู้ว่าตรงไหนที่ไม่สมเหตุผล เพราะไม่รู้ว่าจะเอาข้อมูลที่เชื่อถือได้มาจากไหนดี ก็ต้องรอให้มีคนร้องทุกข์มาพอสมควรก่อน<br><br>อย่างเรื่องวีซ่าที่เราบ่นมา แท้ที่จริงไม่ว่าจะได้มาแบบ J1 หรือ F1 ก็จะตกอยู่ในสภาพที่คล้าย ๆ กันทั้งคู่<br>และที่จริงแบบ J1 ก็ดีกว่า F1 ในกรณีที่มีคู่สมรสมาอยู่ด้วย เพราะ J2 ที่ติดสอยห้อยตามมา สามารถทำงานได้อย่างเต็มรูปแบบ ส่วน F2 ทำงานไม่ได้<br><br>ผมเองก็เลี้ยงชีพด้วยตัวเอง ไม่ได้ขอเงินพ่อแม่มา ถ้าทาง กพ เค้าไม่เงินค่าตั๋วเครื่องบินมาเรียน ผมก็แทบจะไม่เงินซื้อตั๋วเครื่องบินมาที่นี่ด้วยซ้ำ เรียกได้ว่าก่อนมา ผมจนยิ่งกว่าวันเสียอีก และนักเรียนทุนที่นี่จำนวนมากก็อยู่ด้วยกำลังของตัวอง แม้แต่รูมเมตผมก็เป็น วันอย่าได้มองโลกในแง่ร้ายเกินกว่าเหตุเลย<br><br>ครอบครัวไทยบางกลุ่มอยากให้ลูกเป็นข้าราชการเพราะไม่อยากให้ลำบากก็มี อยากให้เป็นใหญ่เป็นโตเพื่อคอรับชันก็มี <br>แต่บางกลุ่มก็ไม่ได้เป็นอย่างนั้น กลุ่มที่ดี ๆ ก็มีอยู่ แต่เราไม่เจอเอง เพราะข้าราชการครูหรือแพทย์ในพื้นที่ห่างไกลก็มีอยู่ พ่อแม้เค้าก็คงไม่อยากจะให้ลูกทำงานแบบนี้สักเท่าไหร่ แต่ในเมื่อเค้าเห็นลูกเต็มไปด้วยจิตวิญญาณที่จะช่วยคนอื่น พร้อมที่จะเผชิญทุกข์น้อยใหญ่ เค้าจึงยอมให้ไปเป็นข้าราชการ ทั้ง ๆ ที่รู้ว่าจะต้องลำบาก<br><br>ผมจบมาจากวิศวะจุฬา โอกาสทางการเงินผมก็มีอยู่ไม่น้อย ยิ่งไปกว่านั้นทั้ง ๆ ที่ผมก็ไม่มีเงิน (พ่อแม่ไม่มีจะให้เหมือนกัน) แต่อยากจะช่วยเหลือพัฒนาคุณภาพการศึกษา จึงได้เลือกเดินทางนี้ พ่อแม่ผมก็ห่วงว่าจะลำบาก (ในดวงของผม พ่อบอกว่าผมจะต้องทำงานหนักไปจนแก่โน่นแหละ ไม่ได้สบายเหมือนคนอื่นเลย) แต่สุดท้ายเค้าก็ยอมให้มาทางนี้ เพราะไม่อาจจะขวางกั้นเจตนาในการทำความดีของคนอื่นได้ และได้แต่หวังว่าผมจะหาทางเอาตัวรอดได้ และไม่ต้องลำบากนัก<br><br>วันอาจจะหลงคิดว่า สมัครทุนนี้มาเป็นการขายจิตวิญญาณ แต่สำหรับผมมันไม่ได้เป็นอย่างนั้นเลย เพราะผมสมัครทุนเพื่อจิตวิญญาณของผมเองต่างหาก ผมเตรียมใจที่จะเผชิญทุกข์ไว้ก่อนล่วงหน้า มีความพร้อมที่จะสละความสุขส่วนตนออก แม้จะเป็นไปเพื่อคนจำนวนมากที่ผมไม่รู้จักก็ตามที <br><br>ทีนี้ถ้าวกกลับมาเรื่องของเงิน มาดูกันดีกว่าอะไรที่ทำให้มันเกิดความแตกต่างขึ้น เพราะผมก็อยู่อย่างมีความสุข <br>อันที่จริงผมก็ไม่ใช่คนประหยัด คือไม่ประหยัดในแง่ที่ว่าผมอยากได้อะไรผมก็ซื้อเหมือนกัน แต่มันต่างกันตรงที่ว่า ผมไม่ค่อยอยากได้อะไรต่างหาก<br><br>ผมสังเกตคนรอบข้าง เค้าก็ไปเที่ยวโน่นเที่ยวนี่บ่อย ๆ บางคนก็ต้องหาซื้อ smart phone ที่ราคาไม่ค่อยจะถูกเท่าไหร่มาใช้ ว่ากันตามเหตุนี้แล้ว นี่ไม่ใช่ความประพฤติของลูกคนจนเลย (คนจนในที่นี้หมายถึงประเทศไทย) แต่ผมพอใจในสิ่งที่ตนมีอยู่ ผมก็มีความสุขของผมได้ด้วยกำลังทรัพย์เพียงน้อยนิด<br><br>ผมไม่ต้องเสียเงินเดินทางไกล เพราะใจไม่เร่าร้อนด้วยการแสวงหาสิ่งภายนอก ผมไม่ต้องเสียเงินเล่นสกี เพราะใจไม่เร่าร้อนด้วยความกระหายที่จะเพลิดเพลินในกีฬา ผมไม่ต้องกระเสือกกระสนหาความรักความปรารถนานอกกายอะไรมาก จึงไม่ต้องเสียเงินเพียงเพื่อให้ได้พบให้ได้ปรนเปรอหญิงหรือชายที่เราพอใจ <br><br>เมื่อใจไม่เร่าร้อน กายก็ไม่เร่าร้อน เมื่อกายไม่เร่าร้อน ก็ไม่ต้องแสวงหา และก็ไม่ต้องมีค่าใช้จ่ายเพื่อปรนเปรอตนหรือคนที่เราหลงให้มากมายนัก <br><br>ผมมาที่นี่ เงินเก็บผมมีแต่จะเพิ่ม ทั้ง ๆ ที่ไม่ได้พยายามเก็บ เพราะในเมื่อใจไม่อยากได้ ก็ไม่ต้องอดกลั้นพยายามเก็บเงิน แต่เงินจะถูกเก็บขึ้นมาเรื่อย ๆ โดยอัตโนมัติ ด้วยเหตุอันแสนจะเข้าใจง่ายคือมันไม่ถูกเอาไปใช้ ผมที่ไม่เป็นหนี้มาก่อน ก็ไม่เป็นเป็นหนี้ต่อไป<br><br>"จิตเป็นาย กายเป็นบ่าว" นะ&nbsp; ใจของเราจะต้องชุ่มโชกด้วยความอยากก่อน กายถึงจะหลงและเร่าร้อนด้วยความอยากได้<br><br>ปัญหาเรื่องค่ากินอยู่ แก้ได้เราก็แก้ แก้ไม่ได้ก็อย่าไปทุกข์ อย่าไปต่อว่าคนอื่นจนเกินเลย คนมีปัญญาเค้ากล่าวไว้ว่า "ปัญหาเป็นสิ่งที่ทุกคนต้องเผชิญ แต่ความทุกข์เป็นเพียงส่วนเกินของชีวิต"<br><br>ย้อนดูคนในอดีต แม้แต่พระพุทธเจ้า พระเยซู ก็ยังต้องเผชิญปัญหาจากสาวกที่ไม่รักดีของตัวเอง คนธรรมดาเดินดินกินข้าวแกงอย่างเราจะหลีกเร้นจากปัญหาก็คงไม่ได้ แต่จะทุกข์หรือเปล่าก็เป็นอีกเรื่องหนึ่ง<br><br>อย่าลืมที่ผมพูดไว้ตอนก่อนหน้านี้นะว่า แม้แต่นิสัยบางอย่างของเราที่เราไม่ชอบ เราก็อาจจะแก้ไม่ได้ ความเขลาบางอย่างที่เรามีอยู่ บางทีเราก็กำจัดออกไปไม่ได้เหมือนกัน เว้นแต่เราจะมีความเด็ดเดี่ยวอย่างต่อเนื่องและยาวนาน<br>เช่น คนติดเหล่า บุหรี่ วีดีโอเกม บางทีก็ติดอยู่นั่นแหละ เป็นสิบปีก็ยังติดอยู่ ทั้งที่รู้ว่าไม่ดีหรือไม่มีประโยชน์<br><br>บุคคลหรือหน่วยงานอื่น ๆ ก็อาจจะตกอยู่ในสภาพนี้ ปัญหาอันไหนที่เรามีกำลังพอแก้ได้ เราก็พยายามแก้ไป ไม่ปล่อยให้เวลาล่วงเลยไปเปล่า ๆ อะไรที่แก้ไม่ได้ก็ต้องยอมรับสภาพมัน เพราะรู้อยู่แก่ใจแล้วว่าได้ทำดีที่สุดแล้ว<br><br>ภิญโญ <br>กรกฎาคม 2552<br>pinyotaehttp://www.blogger.com/profile/08056348551542825367noreply@blogger.com0tag:blogger.com,1999:blog-7454278.post-55073341071403835672009-06-26T04:10:00.001-04:002009-06-26T04:10:55.708-04:00Creating and using shared library in LinuxCreating a shared library is relatively easy.&nbsp; We only need to set a compilation flat to -fPIC (Position Independent Code) to create a library that is usable by other programs.<br><br>To use the shared library, however, is quite tricky in Linux.&nbsp; A shared library or dynamically linked library in Windows are easy to use.&nbsp; We can just place a dll file to the same folder of an executable.&nbsp; <br><br>In Linux, nonetheless, things are more complicated, because Linux will never try to search for a library in a current directory.&nbsp; Thus, we have to add a library direction to a search path or install it to a standard place like /usr/lib.&nbsp; The latter choice needs adminstrator priviledge and not suitable if only one or two programs are to use the library.&nbsp; So, we should modify a search path.<br><br>Now, the question is 'Can we modify a search path, but cause no side effect to other programs at all?'.&nbsp; We are curious about this since we may have multiple libraries of the same name during testing.&nbsp; A debug program may call a debug library and a release program may call release library of the same name.&nbsp; Fortunately, we can do that, as shown in http://tldp.org/HOWTO/Program-Library-HOWTO/shared-libraries.html (Section 3.5. Installing and Using a Shared Library).<br><br>For example, if a shared library is in the same current directory of an executable my_program we can call<br><font color="#000000"><pre class="PROGRAMLISTING">LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH ./my_program<br><br>If the library is in another folder, such as /home/my_name, the command will be <font color="#000000"><pre class="PROGRAMLISTING">LD_LIBRARY_PATH=/home/my_name:$LD_LIBRARY_PATH ./my_program<br><br>Next question is 'How can we do such thing in Eclipse?'. We can do this in 'Run Configurations...'. Once we finish common configuration, we need to set an environment variable in the 'Environment' tab.<br>Click on the 'New' button. Set Name = LD_LIBRARY_PATH and set the Value = my_lib_dir:$LD_LIBRARY_PATH (change 'my_lib_dir' to the library directory). This is enough for Eclipse settings.<br><br><b>Reference</b><br>http://tldp.org/HOWTO/Program-Library-HOWTO/shared-libraries.html<br></pre></font></pre></font><br>pinyotaehttp://www.blogger.com/profile/08056348551542825367noreply@blogger.com0tag:blogger.com,1999:blog-7454278.post-38808215306880771792009-06-01T01:38:00.002-04:002011-09-24T03:59:31.470-04:00Note on Boost's Multidimensional Array<h1>Note on Boost&#39;s Multidimensional Array</h1>(Jun 1, 2009)<br>(Last update: Mar 28, 2010)<br><br> The Boost C++ library provides an elegant way to handle a multi-dimensional array.&nbsp; We can access an array element in a compact way as usual (A[i][j][k], for example).&nbsp; Boundary checking is performed by assertion which is typically disabled when NDEBUG flag is employed. &nbsp; Because of the use of assertion mechanism, accessing elements outside the range of any dimension does not cause an exception, but a program will be terminated right away.&nbsp; This makes sense because a program normally has no use to access an invalid entry and should be rewritten.&nbsp; Plus, graceful stack unwinding and tracing for exception is not available as a standard way in C++ (there may be a better, standard solution about this in the future, however).&nbsp; Thus, program halting is not a bad idea under a typical C++ circumstance.&nbsp; <br><br>Moreover, we almost always prevent out-of-bound access explicitly in our code and there is little use to do boundary checking again, especially when speed is important.&nbsp; Therefore, in a production release, we can remove the boundary checking to increase program speed by disabling assertion.&nbsp; Note: Alternatively, we can disable this boundary checking by defining <font face="Courier New">BOOST_DISABLE_ASSERTS</font>.<br><br> Besides an example in <a href="http://www.boost.org/doc/libs/1_39_0/libs/multi_array/doc/user.html" id="f8pc" title="Boost website">Boost website</a>, I want to add another example and more explanation that may be helpful for later reference (and people who stumble at this page). &nbsp; In this example, I show that we need to pass boost::multi_array by reference explicitly.&nbsp; Otherwise, modification in a called function will not have any effect (to see the difference, try removing &amp; in a function signature of <font face="courier new">change</font>).&nbsp; Also, there is no exception thrown or caught at all.&nbsp; The program will be terminated if assertion is enabled.<br><br> Another side note, but is important, about Boost&#39;s multidimensional array is that we cannot explicitly reallocate it by using = to an instance of the array.&nbsp; Reassigning an array instance can be done only if both input and output arrays are of the same size.<br><br> For example, because we know only an array size during runtime, some may choose to declare a boost multidimensional array without any initial size.<br><br><font face="courier new"> boost::multi_array&lt;double, 3&gt; arrayTest;</font><br><br> Then, we know at runtime that the size is (size_x, size_y, size_z), so we reallocate the array variable by reassignment (using = ) as follows<br><br><font face="courier new"> arrayTest = boost::multi_array&lt;double, 3&gt;(boost::extents[size_x][size_y][size_z]);</font><br><br> This will not cause an error outright in a release mode without assertion, but a program is very likely to crash later on.&nbsp; A correct way to dynamically reallocate the space for a multidimensional array is to use &#39;resize&#39; function, as shown below.<br><br style="font-family:Courier New"><font face="courier new"> arrayTest.resize(boost::extents[size_x][size_y][size_z]);</font><br><br> Notice that it is boost::extent<i><b>s</b></i> (with s), not just boost::extent (without s).&nbsp; There is boost::extent, but it is another thing.&nbsp; Please don&#39;t get confused with this.<br><br><h3>A correct way to copy centents from one array to another</h3>As discussed earlier, reassigning Boost&#39;s multi-dimensional array may cause an error unless both input and output arrays are equal in size.&nbsp; Thus, a proper way for reassignment is:<br><br>// Assume that the input array is of size: size_x, size_y, and size_z.<br>// 1. resize an output array <br><font face="courier new">outArray.resize( boost::extents[size_x][size_y][size_z] );</font><br style="font-family:Courier New"><br>// 2. now, we can copy contents of an input array by using =<br>outArray = inArray;<br><br><h4>Side note: assigning initial contents of an array when it is declared.</h4>Assigning contents to an array when it is declared is not considered reassignment.&nbsp; Hence, such operation is correctly executed as long as the dimensionality is matched.<br><br>// This content assignment is correct, provided that the dimensionality of the input array is three in this case.<br><font face="courier new">boost::multi_array&lt;double, 3&gt;</font> outArray = inArray;<br><br>The above operation implicitly initialized the size of the outArray to be the same as that of inArray.&nbsp; It is important to note that such implicit size initialization can be done at the declaration only.&nbsp; If we do not assign any content to the array, the length of each dimension is zero.&nbsp; Consequently, content assignment int the following example is an incorrect use.<br><br><font face="courier new">boost::multi_array&lt;double, 3&gt;</font><font face="courier new"> outArray;&nbsp;&nbsp;&nbsp; // since we say nothing else here, the length of the array in each dimension is zero.</font><br style="font-family:Courier New"><font face="courier new">outArray = inArray;&nbsp;&nbsp;&nbsp; // The assignment is not done at the declaration time.&nbsp; <font face="courier new">Therefore, this is reassignment.</font><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // If inArray size does not match with outArray, the error will occur.<br></font><br><h3>How can we know the size of Boost&#39;s multi dimensional array</h3>The size of the array comes in two folds: dimensionality and the array length of each dimension.<br><br><ul><li>To obtain dimensionality<br><font face="courier new">int nNumDims = A.dimensionality;</font><br><br></li><li><font face="courier new">Now, obtain the array length of the i<sup>th</sup> dimension<br>int nLengh = <font face="courier new">A.shape()[i];</font><br><br><font face="verdana">The following example obtains and prints out dimensionality and lengths of an array</font><br><font face="courier new"><br>int nNumDims = A.dimensionality;</font><br style="font-family:Courier New"><font face="courier new">cout &lt;&lt; &quot;Dimensionality = &quot; &lt;&lt; nNumDims &lt;&lt; endl;</font><br style="font-family:Courier New"><br style="font-family:Courier New"><font face="courier new"> // Report size list</font><br style="font-family:Courier New"><font face="courier new"> for (int i = 0; i != nNumDims; ++i) {</font><br style="font-family:Courier New"><font face="courier new">&nbsp;&nbsp;&nbsp;&nbsp; cout &lt;&lt; &quot;Size( &quot; &lt;&lt; i &lt;&lt; &quot; ) = &quot; &lt;&lt; A.shape()[i] &lt;&lt; endl;</font><br style="font-family:Courier New"><font face="courier new">}</font><br><br></font></li></ul><h3>Pitfall: Be careful when Boost&#39;s multi-dimensional array is a class member</h3>Suppose class MyArray has a three dimensional array as a member.&nbsp; Copying contents from one instance of MyArray to another implies copying Boost&#39;s multi-dimensional array, as well.<br>So, make sure that the dimensionalities of input and output arrays match before copying.&nbsp; Alternatively, we need to copy the contents of MyArray instance at declaration.&nbsp; See section &#39;A correct way to copy centents from one array to another&#39; and its side note for detail.<br><br>Example:<br><font face="courier new">MyArray outArray;</font><br style="font-family:Courier New"><font face="courier new">MyArray inArray;</font><br style="font-family:Courier New"><br style="font-family:Courier New"><font face="courier new">// Do something with inArray</font><br style="font-family:Courier New"><font face="courier new">// ...</font><br style="font-family:Courier New"><br style="font-family:Courier New"><font face="courier new">// Now, try to save the contents of inArray to outArray</font><br style="font-family:Courier New"><font face="courier new">outArray = inArray;&nbsp; // Beware! There is reassignment of the array inside.&nbsp; </font><br style="font-family:Courier New"><font face="courier new">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // We have to make sure that all Boost&#39;s multi dimensional arrays inside inArray and outArray match in size.</font><br><br>As discussed in the side note above, however, the following code has no problem.<br><font face="courier new">MyArray inArray;</font><br style="font-family:Courier New"><br style="font-family:Courier New"><font face="courier new">// Do something with inArray</font><br style="font-family:Courier New"><font face="courier new">// ...</font><br style="font-family:Courier New"><br style="font-family:Courier New"><font face="courier new">// Now, try to save the contents of inArray to outArray</font><br><font face="courier new">MyArray outArray = inArray;&nbsp; // Correct!&nbsp; There is no array reassignment, but array initialization at declaration.</font><br><br><br>=============================================<br><br>The following code is an example about assertion and exception throw related to Boost&#39;s multi dimensional array.<br><br><font face="courier new">#include &quot;boost/multi_array.hpp&quot;</font><br style="font-family:Courier New"><br style="font-family:Courier New"><font face="courier new"> using namespace std;</font><br style="font-family:Courier New"><br style="font-family:Courier New"><font face="courier new"> typedef boost::multi_array&lt;double, 3&gt; array3_double;</font><br style="font-family:Courier New"><br style="font-family:Courier New"><font face="courier new"> void change(array3_double&amp; A);</font><br style="font-family:Courier New"><font face="courier new"> void causeException(array3_double&amp; A);&nbsp;&nbsp; &nbsp;<font face="verdana">// In fact, it&#39;s not an exception.&nbsp; Program will be aborted immediately if assertion is enabled.</font></font><br style="font-family:Courier New"><br style="font-family:Courier New"><font face="courier new"> int main() {</font><br style="font-family:Courier New"><font face="courier new"> &nbsp;&nbsp;&nbsp; // Notice that it is extent</font><b style="font-family:Courier New">s</b><font face="courier new">, not just extent.</font><br style="font-family:Courier New"><font face="courier new"> &nbsp;&nbsp; &nbsp;array3_double A(boost::extents[4][3][2]);</font><br style="font-family:Courier New"><br style="font-family:Courier New"><font face="courier new"> &nbsp;&nbsp; &nbsp;int values = 0;</font><br style="font-family:Courier New"><font face="courier new"> &nbsp;&nbsp;&nbsp; for(int i = 0; i != 4; ++i)</font><br style="font-family:Courier New"><font face="courier new"> &nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;for(int j = 0; j != 3; ++j)</font><br style="font-family:Courier New"><font face="courier new"> &nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;for(int k = 0; k != 2; ++k)</font><br style="font-family:Courier New"><font face="courier new"> &nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;A[i][j][k] = values++;</font><br style="font-family:Courier New"><br style="font-family:Courier New"><font face="courier new"> &nbsp;&nbsp;&nbsp; change(A);</font><br style="font-family:Courier New"><br style="font-family:Courier New"><font face="courier new"> &nbsp;&nbsp;&nbsp; // Delete this block if you don&#39;t want a program to halt.</font><br style="font-family:Courier New"><font face="courier new"> &nbsp;&nbsp;&nbsp; // Note: there is no exception thrown.&nbsp; Program will be just terminated.</font><br style="font-family:Courier New"><font face="courier new"> &nbsp;&nbsp;&nbsp; {</font><br style="font-family:Courier New"><font face="courier new"> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try {</font><br style="font-family:Courier New"><font face="courier new"> &nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; causeException(A);</font><br style="font-family:Courier New"><font face="courier new"> &nbsp; &nbsp;&nbsp; &nbsp;&nbsp; } catch(std::exception ex) {</font><br style="font-family:Courier New"><font face="courier new"> &nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp; cout &lt;&lt; &quot;Exception caught:&quot; &lt;&lt; endl;</font><br style="font-family:Courier New"><font face="courier new"> &nbsp; &nbsp;&nbsp; &nbsp; &nbsp;&nbsp;&nbsp;&nbsp; cout &lt;&lt; ex.what() &lt;&lt; endl;</font><br style="font-family:Courier New"><font face="courier new"> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</font><br style="font-family:Courier New"><font face="courier new"> &nbsp;&nbsp;&nbsp; }</font><br style="font-family:Courier New"><br style="font-family:Courier New"><font face="courier new"> &nbsp;&nbsp; &nbsp;cout &lt;&lt; A[3][2][1] &lt;&lt; endl; // check this if you pass by value</font><br style="font-family:Courier New"><font face="courier new"> &nbsp;&nbsp; &nbsp;return 0;</font><br style="font-family:Courier New"><font face="courier new"> }</font><br style="font-family:Courier New"><br><font face="courier new">// The parameter is passed by reference.&nbsp; This is important as the change of A in this function <br>//&nbsp;&nbsp; will not affect the</font><font face="courier new"> original copy if we pass by value (without using &amp; in the parameter).&nbsp; <br>// If we pass by value, the whole thing in</font><font face="courier new"> the original copy will be copied to a local copy of <br>//&nbsp;&nbsp; this function.</font><br style="font-family:Courier New"><font face="courier new"> void change(array3_double&amp; A) {</font><br style="font-family:Courier New"><font face="courier new"> &nbsp;&nbsp; &nbsp;int nNumDims = A.dimensionality;</font><br style="font-family:Courier New"><font face="courier new"> &nbsp;&nbsp; &nbsp;cout &lt;&lt; &quot;Dimensionality = &quot; &lt;&lt; nNumDims &lt;&lt; endl;</font><br style="font-family:Courier New"><br style="font-family:Courier New"><font face="courier new"> &nbsp;&nbsp; &nbsp;// Report size list</font><br style="font-family:Courier New"><font face="courier new"> &nbsp;&nbsp; &nbsp;for (int i = 0; i != nNumDims; ++i) {</font><br style="font-family:Courier New"><font face="courier new"> &nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;cout &lt;&lt; &quot;Size( &quot; &lt;&lt; i &lt;&lt; &quot; ) = &quot; &lt;&lt; A.shape()[i] &lt;&lt; endl;</font><br style="font-family:Courier New"><font face="courier new"> &nbsp;&nbsp; &nbsp;}</font><br style="font-family:Courier New"><br style="font-family:Courier New"><font face="courier new"> &nbsp;&nbsp; &nbsp;// Report total size</font><br style="font-family:Courier New"><font face="courier new"> &nbsp;&nbsp; &nbsp;cout &lt;&lt; &quot;Total size = &quot; &lt;&lt; A.num_elements() &lt;&lt; endl;</font><br style="font-family:Courier New"><br style="font-family:Courier New"><font face="courier new"> &nbsp;&nbsp; &nbsp;A[3][2][1] = 99;</font><br style="font-family:Courier New"><br style="font-family:Courier New"><font face="courier new"> &nbsp;&nbsp; &nbsp;return;</font><br style="font-family:Courier New"><font face="courier new"> }</font><br style="font-family:Courier New"><br style="font-family:Courier New"><font face="courier new"> void causeException(array3_double&amp; A) {</font><br style="font-family:Courier New"><font face="courier new"> &nbsp;&nbsp; &nbsp;int k = 7;</font><br style="font-family:Courier New"><br style="font-family:Courier New"><font face="courier new"> &nbsp;&nbsp; &nbsp;A[5][5][k] = 9999;</font><br style="font-family:Courier New"><br style="font-family:Courier New"><font face="courier new"> &nbsp;&nbsp; &nbsp;return;</font><br style="font-family:Courier New"><font face="courier new"> }</font><br><br><br> =============================================<br><br>Pinyo Taeprasartsit<br><br>(This document can be viewed at <a href="http://pinyotae.blogspot.com/2009/06/note-on-boost-multidimensional-array.html" title="my blog">my blog</a> and <a href="http://docs.google.com/View?id=dggq8h5d_177c59hzpc2" title="Google docs">Google docs</a>)<br>(Feel free to leave comment or question in my blog.&nbsp; Don&#39;t worry if it is an old post.&nbsp; I get a notification of your comment in my mailbox and tend to answer questions from the reader. <br>Google docs version is better for printing.)<br>pinyotaehttp://www.blogger.com/profile/08056348551542825367noreply@blogger.com6