• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            曠野的呼聲

            路漫漫其修遠兮 吾將上下而求索

            常用鏈接

            統計

            最新評論

            2010年1月5日 #

            難得上cppblog一次,分享一本書吧。《Pro Visual C++/CLI and The .NET3.5 Platform》英文清晰PDF版本

            地址在這里

            另外分享一小段沒什么用處的測試代碼:


            #include <iostream>
            #include 
            <string>
            #include 
            <list>
            #include 
            <algorithm>

            #include 
            <vcclr.h>

            using namespace System;

            int main()
            {
                std::list
            <int> lstTest;

                std::copy( 
                    std::istream_iterator
            <int>(std::cin), 
                    std::istream_iterator
            <int>(), 
                    std::back_insert_iterator
            < std::list<int> >( lstTest ) 
                    );

                System::Collections::Generic::List
            <int>^ lstCLR = gcnew Collections::Generic::List<int>();

                
            for( std::list<int>::const_iterator it = lstTest.begin();
                    it 
            != lstTest.end();
                    
            ++it )
                {
                    lstCLR
            ->Add( *it );
                }

                printf_s( 
            "-----------------------------------------\n" );

                lstCLR
            ->Sort();

                
            for each( int i in lstCLR )
                {
                    Console::WriteLine( i );
                }

                System::Collections::Generic::List
            < String^ >^ lstString = gcnew Collections::Generic::List<String^>();

                
            forint i =0; i < 10++i )
                {
                    wchar_t sz[
            12];
                    swprintf_s( sz, L
            "%d", i );

                    lstString
            ->Add( gcnew String( sz ) );
                }

                std::list
            <std::wstring> lstStdString;

                
            for each( String^ Str in lstString )
                {
                    pin_ptr
            < const wchar_t > pStr = PtrToStringChars( Str );

                    lstStdString.push_back( std::wstring( pStr ) );
                }

                 std::copy( lstStdString.begin(), 
                     lstStdString.end(), 
                     std::ostream_iterator
            < std::wstring, wchar_t >( std::wcout, L"\n" )
                     );
                 

                
            return 0;
            }

             這才是我經常活動的家

            posted @ 2010-01-05 16:42 董波 閱讀(630) | 評論 (0)編輯 收藏

            2009年9月12日 #

            柏林噪聲 perlin noise

            Perlin Noise  在wikipia上,可以查到定義,這里不多說了,http://freespace.virgin.net/hugo.elias/models/m_perlin.htm 上有完整的英文,http://www.azure.com.cn/article.asp?id=291 是帶有翻譯的英文, 看來這篇文章是原始作者的大作了。轉帖過來

            柏林噪聲(Perlin Noise)(譯)
            原文鏈接:http://freespace.virgin.net/hugo.elias/models/m_perlin.htm
            翻譯:azure

            Many people have used random number generators in their programs to create unpredictability, make the motion and behavior of objects appear more natural, or generate textures. Random number generators certainly have their uses, but at times their output can be too harsh to appear natural. This article will present a function which has a very wide range of uses, more than I can think of, but basically anywhere where you need something to look natural in origin. What's more it's output can easily be tailored to suit your needs.
            很多人在他們的程序中使用隨機數生成器去創造不可預測,使物體的行為和運動表現的更加自然,或者生成紋理。隨機數生成器當然是有他們的用途的,但是它們似乎過于苛刻。這篇文章將會展示一個用途十分廣泛的功能,甚至其用途比我想到的還要廣泛,其結果可以輕易的適合你的需求。

            If you look at many things in nature, you will notice that they are fractal. They have various levels of detail. A common example is the outline of a mountain range. It contains large variations in height (the mountains), medium variations (hills), small variations (boulders), tiny variations (stones) . . . you could go on. Look at almost anything: the distribution of patchy grass on a field, waves in the sea, the movements of an ant, the movement of branches of a tree, patterns in marble, winds. All these phenomena exhibit the same pattern of large and small variations. The Perlin Noise function recreates this by simply adding up noisy functions at a range of different scales.
            如果你觀察自然界中很多事物,你會注意到它們是分形的。它們有著很多層次細節。最平常的例子是山峰輪廓。它包含著高度上的很大變化(山峰),中等變化(丘陵),小的變化(礫石),微小變化(石頭)...你可以繼續想象。觀察幾乎所有事物:片狀分布于田間草,海中的波浪,螞蟻的運動方式,樹枝的運動,大理石的花紋,風。所有這些現象表現出了同一種的大小的變化形式。柏林噪聲函數通過直接添加一定范圍內,不同比例的噪聲函數來重現這種現象。

            To create a Perlin noise function, you will need two things, a Noise Function, and an Interpolation Function.
            為了創建一個柏林噪聲函數,我們需要兩個東西,一個噪聲函數和一個插值函數。

            Introduction To Noise Functions
            噪聲函數介紹

            A noise function is essentially a seeded random number generator. It takes an integer as a parameter, and returns a random number based on that parameter. If you pass it the same parameter twice, it produces the same number twice. It is very important that it behaves in this way, otherwise the Perlin function will simply produce nonsense.
            一個噪聲函數基本上是一個種子隨機發生器。它需要一個整數作為參數,然后返回根據這個參數返回一個隨機數。如果你兩次都傳同一個參數進來,它就會產生兩次相同的數。這條規律非常重要,否則柏林函數只是生成一堆垃圾。




            Here is a graph showing an example noise function. A random value between 0 and1 is assigned to every
            point on the X axis.
            這里的一張圖展現了噪聲函數的一個例子。X軸上每個點被賦予一個0到1之間的隨機數。


            By smoothly interpolating between the values, we can define a continuous function that takes a non-integer as a parameter. I will discuss various ways of interpolating the values later in this article.
            通過在值之間平滑的插值,我們定義了一個帶有一個非整參數的連續函數。我們將會在后面的內容中討論多種插值方式

            Definitions
            定義

            Before I go any further, let me define what I mean by amplitude and frequency. If you have studied physics, you may well have come across the concept of amplitude and frequency applied to a sin wave.
            當我們準備深入之前,讓我定義下什么是振幅(amplitude)和頻率(frequency)。如果你學過物理,你可能遇到過在正玄波中振幅(amlitude)和頻率(frequency)的概念。


            Sin Wave
            The wavelength of a sin wave is the distance from one peak to another. The amplitude is the height of the wave. The frequency is defined to be 1/wavelength.
            正玄波
            正玄波的波長(wavelength)是兩個波峰只間的距離。振幅是此波的高度。頻率我們定義為 1/波長(wavelength)。


            Noise Wave
            In the graph of this example noise function, the red spots indicate the random values defined along the dimension of the function. In this case, the amplitude is the difference between the minimum and maximum values the function could have. The wavelength is the distance from one red spot to the next. Again frequency is defined to be 1/wavelength.
            噪聲波
            圖中這個噪聲波的例子中,紅點表示定義沿著在函數維上的隨機值。在這種情況下,振幅是這個函數的最大值與最小值的差值。波長(wavelength)是兩個紅點之間的距離。同樣的頻率(frequency)定義為1/波長(wavelength).

            Creating the Perlin Noise Function
            創建柏林噪聲函數

            Now, if you take lots of such smooth functions, with various frequencies and amplitudes, you can add them all together to create a nice noisy function. This is the Perlin Noise Function.
            現在,如果你使用很多平滑函數,分別擁有各種各樣的頻率和振幅,你可以把他們疊加在一起來創建一個漂亮的噪聲函數。這個就是柏林噪聲函數。

            Take the following Noise Functions
            使用以下的噪聲函數



            Add them together, and this is what you get.
            將他們疊加起來,你將會得到:-)


            You can see that this function has large, medium and small variations. You may even imagine that it looks a little like a mountain range. In fact many computer generated landscapes are made using this method. Of course they use 2D noise, which I shall get onto in a moment.
            你能發現這個函數擁有大的,中的和小的變化。你甚至可以它已經有點像山的輪廓了。事實上很多電腦生成地形景觀也是使用了這種方法,當然那使用的是2D的噪聲,我們將過一下來研究這個。

            You can, of course, do the same in 2 dimensions.
            你當然同樣的可以在二維下也這么做。

            Some noise functions are created in 2D
            一些2D的噪聲函數




            Adding all these functions together produces a noisy pattern.
            把這些函數疊加起來產生的噪聲樣式。



            Persistence
            持續度

            When you're adding together these noise functions, you may wonder exactly what amplitude and frequency to use for each one. The one dimensional example above used twice the frequency and half the amplitude for each successive noise function added. This is quite common. So common in fact, that many people don't even consider using anything else. However, you can create Perlin Noise functions with different characteristics by using other frequencies and amplitudes at each step. For example, to create smooth rolling hills, you could use Perlin noise function with large amplitudes for the low frequencies , and very small amplitudes for the higher frequencies. Or you could make a flat, but very rocky plane choosing low amplitudes for low frequencies.
            當你把噪聲函數疊加的時候,你可能想了解每次具體使用了什么振幅和頻率。上面一維的例子對于每個連續疊加的噪聲函數使用了兩倍的頻率和二分之一倍的振幅。這個太普通了,事實上太普通,以至于很多人甚至從來都沒有考慮過使用其他什么。盡管如此,你可以通過在每步使用其他的頻率和振幅來創建不同特征的柏林噪聲函數。例如,為了創建一個平滑滾動的丘陵,你可以使用大的振幅和小的頻率的柏林噪聲函數,同時小的振幅和高的頻率,你可以創建一個平地,另外要創建非常顛簸的平面,應該選擇小的振幅和低的頻率。

            To make it simpler, and to avoid repeating the words Amplitude and Frequency all the time, a single number is used to specify the amplitude of each frequency. This value is known as Persistence. There is some ambiguity as to it's exact meaning. The term was originally coined by Mandelbrot, one of the people behind the discovery of fractals. He defined noise with a lot of high frequency as having a low persistence. My friend Matt also came up with the concept of persistence, but defined it the other way round. To be honest, I prefer Matt's definition. Sorry Mandelbrot. So our definition of persistence is this:
            為了讓這些更簡單易懂,同時為了避免重復振幅和頻率這兩個詞,我們用一個數來表示每個頻率下的振幅,這個數就是持續度(Persistence)。這里的詞和它的真實意義有些歧異。這個術語原本是Mandelbrot提出的,他是發現分形現象的人中的一個。他定義噪聲擁有大量的高頻率將體現出低的持續度。我的朋友Matt也想出了持續度的概念,但是是通過另外一種方式定義它的。誠然,我更喜歡Matt的定義方式。對不起了,Mandelbrot. 所以我們這樣定義持續度(persistence):
            frequency = 2i
            amplitude = persistencei
            Where i is the ith noise function being added. To illustrate the effect of persistence on the output of the Perlin Noise, take a look at the diagrams below. They show the component noise functions that are added, the effect of the persistence value, and the resultant Perlin noise function.
            i 是表示第i個被疊加的噪聲函數。為了展示柏林函數在輸出上持續度的表現效果,請看下下面的圖表。他們展示了疊加的每個組成部分,持續度的效果和最終的柏林函數。



            Octaves
            倍頻

            Each successive noise function you add is known as an octave. The reason for this is that each noise function is twice the frequency of the previous one. In music, octaves also have this property.
            每個你所疊加的噪聲函數就是一個倍頻。因為每一個噪聲函數是上一個的兩倍頻率。在音樂上,倍頻也有著這項屬性。

            Exactly how many octaves you add together is entirely up to you. You may add as many or as few as you want. However, let me give you some suggestions. If you are using the perlin noise function to render an image to the screen, there will come a point when an octave has too high a frequency to be displayable. There simply may not be enough pixels on the screen to reproduce all the little details of a very high frequency noise function. Some implementations of Perlin Noise automatically add up as many noise functions they can until the limits of the screen (or other medium) are reached.
            具體多少倍頻你疊加在一起,這完全取決于你。你可以疊加很多也可以很少。盡管如此,還是讓我給你一些建議吧。如果你正使用柏林噪聲函數在屏幕上渲染圖象的話,如果倍頻頻率太高將會使縮成一個點以至于不能顯示,這就是因為你屏幕的分辨率不夠。一些柏林噪聲函數的實現會自動疊加噪聲函數直到達到屏幕分辨率的極限。

            It is also wise to stop adding noise functions when their amplitude becomes too small to reproduce. Exactly when that happens depends on the level of persistence, the overall amplitude of the Perlin function and the bit resolution of your screen (or whatever).
            當振幅變的很小的時候,也應該明智的停止再疊加噪聲函數。屆時當發生依靠持續度的等級,柏林函數整體的振幅和屏幕的分辨率(翻譯的爛)。

            Making your noise functions
            創造你的噪聲函數

            What do we look for in a noise function? Well, it's essentially a random number generator. However, unlike other random number generators you may have come across in your programs which give you a different random number every time you call them, these noise functions supply a random number calculated from one or more parameters. I.e. every time you pass the same number to the noise function, it will respond with the same number. But pass it a different number, and it will return a different number.
            我們需要什么樣的噪聲函數?好,基本上就是一個隨機數發生器。盡管如此,它不像你在程序中遇到的那中每次調用它都返回不同的隨機數的隨機函數,這些噪聲函數生成一個隨機數是通過一個或者多個參數計算而來。例如,每次你傳入一個相同的數到噪聲函數里,它將每次也返回相同的隨機數。但是如果傳入一個不同的數,那么它又將返回一個不同的數,

            Well, I don't know a lot about random number generators, so I went looking for some, and here's one I found. It seems to be pretty good. It returns floating point numbers between -1.0 and1.0.
            好,我對隨機數生成器并不懂太多,所以我去找了一些,這里我找到了一個,好象很好用。它返回一個浮點數,范圍是-1.0到1.0
            function IntNoise(32-bit integer: x)      

            x = (x<<13) ^ x;
            return ( 1.0 - ( (x * (x * x * 15731 + 789221) + 1376312589) & 7fffffff) / 1073741824.0);
            end IntNoise function
            Now, you'll want several different random number generators, so I suggest making several copies of the above code, but use slightly different numbers. Those big scarey looking numbers are all prime numbers, so you could just use some other prime numbers of a similar size. So, to make it easy for you to find random numbers, I have written a little program to list prime numbers for you. You can give it a start number and an end number, and it will find all the primes between the two. Source code is also included, so you can easily include it into your own programs to produce a random prime number. Primes.zip
            現在,你將要需要幾個不同的隨機數生成器,所以我建議把上面的代碼復制幾個拷貝,然后稍微修改下里面的參數。那些可怕的數字都是質數,所以你可以改成其他差不多大小的質數(讓我想起了 hash key生成),為了讓你輕松的找的隨機數,我已經寫了一個小程序來為你列出質數。你只用輸入一個起始值和一個結束值,它找到所有在兩值之間的質數。源代碼也提供,所以你可以輕松的包含到你自己的程序中來生成隨機的質數.Primes.zip

            Interpolation
            插值

            Having created your noise function, you will need to smooth out the values it returns. Again, you can choose any method you like, but some look better than others. A standard interpolation function takes three inputs, a and b, the values to be interpolated between, and x which takes a value between 0 and1. The Interpolation function returns a value between a and b based on the value x. When x equals 0, it returns a, and when x is 1, it returns b. When x is between 0 and1, it returns some value between a and b.
            當創建了你的噪聲函數,你將需要平滑下他的返回值。再次,你可以選擇任何你喜歡的方式,但是有一些效果更好。一個標準的插值函數需要三個輸入,a 和 b, 需要在a和b之間進行插值,還有x,它取值范圍是0到1。插值函數返回a到b之間取決與x的一個值。當x等于0,它返回a,當x等于1時,它返回b。當x 是0到1之間時,它將返回a到b之間的某值。

            Linear Interpolation:
            線性插值

            Looks awful, like those cheap 'plasmas' that everyone uses to generate landscapes. It's a simple algorithm though, and I suppose would be excusable if you were trying to do perlin noise in realtime.
            看起來很齷齪的,像那些每個人用來生成地形的廉價'plasmas'一樣,它是一個簡單的算法,如果你想實時的使用柏林噪聲函數,這種插值方式是一個選擇。

            function Linear_Interpolate(a, b, x)
              return a*(1-x) + b*x
            end of function
            Cosine Interpolation:
            余玄插值

            This method gives a much smother curve than Linear Interpolation. It's clearly better and worth the effort if you can afford the very slight loss in speed.
            這個方法線性插值生成了更平滑的曲線。它當然有著更好的效果,如果你愿意稍微損失點速度的話。

            function Cosine_Interpolate(a, b, x)
              ft = x * 3.1415927
              f = (1 - cos(ft)) * .5

              return a*(1-f) + b*f
            end of function
            Cubic Interpolation:
            立方插值:

            This method gives very smooth results indeed, but you pay for it in speed. To be quite honest, I'm not sure if it would give noticeably better results than Cosine Interpolation, but here it is anyway if you want it. It's a little more complicated, so pay attention. Whereas before, the interpolation functions took three inputs, the cubic interpolation takes five. Instead of just a and b, you now need v0, v1, v2 and v3, along with x as before.
            這個方法的確是生成了非常平滑的結果,但是你付出的代價就是速度。老實說,我不那么確定它能給你比余玄插值好很多的效果,但是如果你無論如何要使用它的話,它有一點點的復雜,所以這里請注意,之前,插值函數只需要三個參數,但是立方插值需要五個,取代了a和b,現在你需要v0,v1,v2,v3,x和以前一樣也需要。


            這些是:
            v0 = a 前面一點
            v1 = a 點
            v2 = b 點
            v3 = b 后面一點


            function Cubic_Interpolate(v0, v1, v2, v3,x)
              P = (v3 - v2) - (v0 - v1)
              Q = (v0 - v1) - P
              R = v2 - v0
              S = v1

              return Px3 + Qx2 + Rx + S
            end of function
            Smoothed Noise
            平滑的噪聲

            Aside from Interplolation, you can also smooth the output of the noise function to make it less random looking, and also less square in the 2D and 3D versions. Smoothing is done much as you would expect, and anyone who has written an image smoothing filter, or fire algorithm should already be familiar with the process.
            Rather than simply taking the value of the noise function at a single coordinate, you can take the average of that value, and it's neighbouring values. If this is unclear, take a look at the pseudo code below.
            除了插值,你也可以平滑噪聲函數的輸出來使它看起來不那么隨機,和讓2D和3D的版本少一點方塊。平滑的結果和你所想的差不多,只要是寫過平滑過濾或者火焰算法的人都應該相當熟悉此過程。相比在一個單獨的坐標上取得噪聲值,你可以取平均的噪聲值,和它臨近的值。如果你不清楚這個,可以看看下面的偽代碼。

            On the right, you can see a little diagram illustrating the difference between smoothed noise, and the same noise function without smoothing. You can see that the smooth noise is flatter, never reaching the extremes of unsmoothed noise, and the frequency appears to be roughly half. There is little point smoothing 1 dimensional noise, since these are really the only effects. Smoothing becomes more useful in 2 or three dimensions, where the effect is to reduce the squareness of the noise. Unfortunately it also reduces the contrast a little. The smoother you make it, obviously, the flatterthe noise will be.
            在右面(這里看下面),你可以看見一個小的圖展示了不同平滑函數的區別,和同樣的一個噪聲但未進行平滑處理。你可以看見平滑函數,從來都沒有到底那個未平滑函數的極限值,并且頻率顯得只有大約一半。那里有小點平滑一維的噪聲,只有這一個效果。平滑過程在二維和三維中,顯得更有用處,那就是它減少了噪聲大方塊。不幸的是它也降低了一點對比度。你讓它越平滑,這個噪聲就會越平坦。



            1-dimensional Smooth Noise
            一維噪聲函數
            function Noise(x)
            .
            .
            end function

            function SmoothNoise_1D(x)

            return Noise(x)/2 + Noise(x-1)/4 + Noise(x+1)/4

            end function
            2-dimensional Smooth Noise
            二維噪聲函數
            function Noise(x, y)
            .
            .
            end function

            function SmoothNoise_2D(x>, y)

            corners = ( Noise(x-1, y-1)+Noise(x+1, y-1)+Noise(x-1, y+1)+Noise(x+1, y+1) ) / 16
            sides = ( Noise(x-1, y) +Noise(x+1, y) +Noise(x, y-1) +Noise(x, y+1) ) / 8
            center = Noise(x, y) / 4

            return corners + sides + center

            end function
            Putting it all together
            把它們組合在一起

            Now that you know all that, it's time to put together all you've learned and create a Perlin Noise function. Remember that it's just several Interpolated Noise functions added together. So Perlin Noise it just a function. You pass it one or more parameters, and it responds with a number. So, here's a simple 1 dimensional Perlin function.
            既然你知道了全部這些,現在是時候把他們組合在一起了,你將學會并創建一個柏林函數。記住這知識幾個插值的噪聲函數疊加在一起。所以柏林函數只是一個函數。你傳入一個或多個參數,然后它返回一個數給你。所以很簡單,一維的柏林函數是這樣。

            The main part of the Perlin function is the loop. Each iteration of the loop adds another octave of twice the frequency. Each iteration calls a different noise function, denoted by Noisei. Now, you needn't actually write lots of noise functions, one for each octave, as the pseudo code seems to suggest. Since all the noise functions are essentially the same, except for the values of those three big prime numbers, you can keep the same code, but simply use a different set of prime numbers for each.
            柏林函數重要的部分是那個循環。每次循環跌代疊加另一個兩倍頻率的倍頻。每次跌代調用一個不同的噪聲函數,稱做Noisei。當然,你并不需要真的寫為每個倍頻很多噪聲函數,偽代碼中好象只是建議這么做。既然所有的噪聲函數實際上都是相同的,除了那三個大質數不同除外,你可以使用同樣的代碼,只是每個代碼改用不同的質數。

            1-dimensional Perlin Noise Pseudo code
            一維柏林噪聲函數偽代碼
            function Noise1(integer x)
            x = (x<<13) ^ x;
            return ( 1.0 - ( (x * (x * x * 15731 + 789221) + 1376312589) & 7fffffff) / 1073741824.0);
            end function

            function SmoothedNoise_1(float x)
            return Noise(x)/2 + Noise(x-1)/4 + Noise(x+1)/4
            end function

            function InterpolatedNoise_1(float x)

            integer_X = int(x)
            fractional_X = x - integer_X

            v1 = SmoothedNoise1(integer_X)
            v2 = SmoothedNoise1(integer_X + 1)

            return Interpolate(v1 , v2 , fractional_X)

            end function

            function PerlinNoise_1D(float x)

            total = 0
            p = persistence
            n = Number_Of_Octaves - 1

            loop i from 0 to n

            frequency = 2i
            amplitude = pi

            total = total + InterpolatedNoisei(x * frequency) * amplitude

            end of i loop

            return total

            end function
            Now it's easy to apply the same code to create a 2 or more dimensional Perlin Noise function:
            現在可以輕松的使用同樣的代碼創建二維或者多維的柏林噪聲函數了:

            2-dimensional Perlin Noise Pseudocode
            二維柏林噪聲函數偽代碼
            function Noise1(integer x, integer y)
            n = x + y * 57
            n = (n<<13) ^ n;
            return ( 1.0 - ( (n * (n * n * 15731 + 789221) + 1376312589) & 7fffffff) / 1073741824.0);
            end function

            function SmoothNoise_1(float x, float y)
            corners = ( Noise(x-1, y-1)+Noise(x+1, y-1)+Noise(x-1, y+1)+Noise(x+1, y+1) ) / 16
            sides = ( Noise(x-1, y) +Noise(x+1, y) +Noise(x, y-1) +Noise(x, y+1) ) / 8
            center = Noise(x, y) / 4
            return corners + sides + center
            end function

            function InterpolatedNoise_1(float x, float y)

            integer_X = int(x)
            fractional_X = x - integer_X

            integer_Y = int(y)
            fractional_Y = y - integer_Y

            v1 = SmoothedNoise1(integer_X, integer_Y)
            v2 = SmoothedNoise1(integer_X + 1, integer_Y)
            v3 = SmoothedNoise1(integer_X, integer_Y + 1)
            v4 = SmoothedNoise1(integer_X + 1, integer_Y + 1)

            i1 = Interpolate(v1 , v2 , fractional_X)
            i2 = Interpolate(v3 , v4 , fractional_X)

            return Interpolate(i1 , i2 , fractional_Y)

            end function

            function PerlinNoise_2D(float x, float y)

            total = 0
            p = persistence
            n = Number_Of_Octaves - 1

            loop i from 0 to n

            frequency = 2i
            amplitude = pi

            total = total + InterpolatedNoisei(x * frequency, y * frequency) * amplitude

            end of i loop

            return total

            end function

            本文來自CSDN博客,轉載請標明出處:http://blog.csdn.net/anywn1314/archive/2007/10/15/1825765.aspx

            posted @ 2009-09-12 21:15 董波 閱讀(1960) | 評論 (0)編輯 收藏

            2009年8月28日 #

            有人問為什么游戲資源要打包。

            相對而言,對比較小,而且多的文件打包是很有意義的,這也是為什么越來越多的游戲對聲音資源不打包的原因。

            在桌面上新建一個文本文件,寫入abcd四個字母,右擊它,屬性,大小:4字節,占用空間:4.00KB。
            這就是為什么要打包的原因之一。

            另外你可以同時處理大的打包過的文件和一大堆幾萬甚至幾十萬個文件,速度會不同的。前者要快些。同時打包還可以對文件進行加密、壓縮等等。

            可見打包美術資源還是很有意義的,而且還有一個好處,看起來Cool!一些。

            posted @ 2009-08-28 10:33 董波 閱讀(558) | 評論 (0)編輯 收藏

            2009年6月10日 #

            【原創】游戲中的聲音資源打包

                 摘要: 游戲中的聲音資源打包 董波 介紹 在以前的游戲當中,幾乎所有的游戲都有將資源打包,無論是圖形資源、聲音文件等等。現在,越來越多的游戲的聲音資源都公開了,通常背景音樂等采用ogg,音效采用wav;但是圖形資源絕大部分游戲還是都是打包了的。有的有加密,有的沒有。 在學習游戲編程的初期我就對這個東西很感興趣,但是又沒有人教,到網上找資料也少得可憐,所以就只好自己摸索了。記得去年也做過類似的工作,...  閱讀全文

            posted @ 2009-06-10 23:43 董波 閱讀(1810) | 評論 (0)編輯 收藏

            2009年5月25日 #

            【轉帖】Rational Purify 使用及分析實例

            Rational Purify 使用及分析實例

            developerWorks

            級別: 初級

            蔡 林, IBM 中國軟件開發中心軟件工程師

            2006 年 2 月 23 日

            本文介紹了 IBM Rational Purify的基本概念和在不同操作系統中使用Purify對C/C++源程序中存在的內存問題進行勘察和分析,并且提供了有關的實例以便讀者在實際操作中作為參考。

            簡介

            本文介紹了IBM Rational Purify的基本概念和在不同操作系統中使用Purify對C/C++源程序中存在的內存問題進行勘察和分析,并且提供了有關的實例以便讀者在實際操作中作為參考。






            1.內存問題的原因及分類

            在C/C++程序中,有關內存使用的問題是最難發現和解決的。這些問題可能導致程序莫名其妙地停止、崩潰,或者不斷消耗內存直至資源耗盡。由于C/C++語言本身的特質和歷史原因,程序員使用內存需要注意的事項較多,而且語言本身也不提供類似Java的垃圾清理機制。編程人員使用一定的工具來查找和調試內存相關問題是十分必要的。

            總的說來,與內存有關的問題可以分成兩類:內存訪問錯誤和內存使用錯誤。內存訪問錯誤包括錯誤地讀取內存和錯誤地寫內存。錯誤地讀取內存可能讓你的模塊返回意想不到的結果,從而導致后續的模塊運行異常。錯誤地寫內存可能導致系統崩潰。內存使用方面的錯誤主要是指申請的內存沒有正確釋放,從而使程序運行逐漸減慢,直至停止。這方面的錯誤由于表現比較慢很難被人工察覺。程序也許運行了很久才會耗凈資源,發生問題。

            1.1 內存解剖

            一個典型的C++內存布局如下圖所示:



            自底向上,內存中依次存放著只讀的程序代碼和數據,全局變量和靜態變量,堆中的動態申請變量和堆棧中的自動變量。自動變量就是在函數內聲明的局部變量。當函數被調用時,它們被壓入棧;當函數返回時,它們就要被彈出堆棧。堆棧的使用基本上由系統控制,用戶一般不會直接對其進行控制,所以堆棧的使用還是相對安全的。動態內存是一柄雙刃劍:它可以提供程序員更靈活的內存使用方法,而且有些算法沒有動態內存會很難實現;但是動態內存往往是內存問題存在的沃土。

            1.2 內存訪問錯誤

            相對用戶使用的語言,動態內存的申請一般由malloc/new來完成,釋放由free/delete完成。基本的原則可以總結為:一對一,不混用。也就是說一個malloc必須對應一且唯一的free;new對應一且唯一的delete; malloc不能和delete, new不能和free對應。另外在C++中要注意delete和delete[]的區別。delete用來釋放單元變量,delete[]用來釋放數組等集聚變量。有關這方面的詳細信息可以參考[C++Adv]。

            我們可以將內存訪問錯誤大致分成以下幾類:數組越界讀或寫、訪問未初始化內存、訪問已經釋放的內存和重復釋放內存或釋放非法內存。

            下面的代碼集中顯示了上述問題的典型例子:


            1   #include <iostream>
                                    2   using namespace std;
                                    3   int main(){
                                    4      char* str1="four";
                                    5      char* str2=new char[4];	//not enough space
                                    6      char* str3=str2;
                                    7      cout<<str2<<endl;	//UMR
                                    8      strcpy(str2,str1);	//ABW
                                    9      cout<<str2<<endl;  //ABR
                                    10     delete str2;
                                    11     str2[0]+=2;	//FMR and FMW
                                    12     delete str3;	//FFM
                                    13   }
                                    

            由以上的程序,我們可以看到:在第5行分配內存時,忽略了字符串終止符"\0"所占空間導致了第8行的數組越界寫(Array Bounds Write)和第9行的數組越界讀(Array Bounds Read); 在第7行,打印尚未賦值的str2將產生訪問未初始化內存錯誤(Uninitialized Memory Read);在第11行使用已經釋放的變量將導致釋放內存讀和寫錯誤(Freed Memory Read and Freed Memory Write);最后由于str3和str2所指的是同一片內存,第12行又一次釋放了已經被釋放的空間 (Free Freed Memory)。

            這個包含許多錯誤的程序可以編譯連接,而且可以在很多平臺上運行。但是這些錯誤就像定時炸彈,會在特殊配置下觸發,造成不可預見的錯誤。這就是內存錯誤難以發現的一個主要原因。

            1.3 內存使用錯誤

            內存使用錯誤主要是指內存泄漏,也就是指申請的動態內存沒有被正確地釋放,或者是沒有指針可以訪問這些內存。這些小的被人遺忘的內存塊占據了一定的地址空間。當系統壓力增大時,這些越來越多的小塊將最終導致系統內存耗盡。內存使用錯誤比內存訪問錯誤更加難以發現。這主要有兩點原因:第一,內存使用錯誤是"慢性病",它的癥狀可能不會在少數、短時間的運行中體現;第二,內存使用錯誤是因為"不做為"(忘記釋放內存)而不是"做錯"造成的。這樣由于忽略造成的錯誤在檢查局部代碼時很難發現,尤其是當系統相當復雜的時候。






            2.Purify的原理及使用

            IBM Rational PurifyPlus是一組程序運行時的分析軟件。她包括了程序性能瓶頸分析軟件Quantify, 程序覆蓋面分析軟件PureCoverage,和本文的主角:程序運行錯誤分析軟件Purify。Purify可以發現程序運行時的內存訪問,內存泄漏和其他難以發現的問題。

            同時她也是市場上唯一支持多種平臺的類似工具,并且可以和很多主流開發工具集成。Purify可以檢查應用的每一個模塊,甚至可以查出復雜的多線程或進程應用中的錯誤。另外她不僅可以檢查C/C++,還可以對Java或.NET中的內存泄漏問題給出報告。

            2.1 Purify的原理

            程序運行時的分析可以采用多種方法。Purify使用了具有專利的目標代碼插入技術(OCI:Object Code Insertion)。她在程序的目標代碼中插入了特殊的指令用來檢查內存的狀態和使用情況。這樣做的好處是不需要修改源代碼,只需要重新編譯就可以對程序進行分析。

            對于所有程序中使用的動態內存,Purify將它們按照狀態進行歸類。這可以由下圖來說明(來自[DEV205]):



            參見本文中以上給出的代碼,在程序第5行執行后,str2處于黃色狀態。當在第7行進行讀的時候,系統就會報告一個訪問未初始化內存錯誤(Uninitialized Memory Read)。因為只有在綠色狀態下,內存才可以被合法訪問。

            為了檢查數據越界錯誤(ABR,ABW),Purify還在每個分配的內存前后插入了紅色區域。這樣一來,超過邊界的訪問指令必定落在非法區域,從而觸發ABR或者ABW錯誤報告。這里需要指出一點。訪問未初始化內存錯誤UMR在某些情況下其實是合法的操作,例如內存拷貝。所以在分析報告時可以把UMR放到最后,或者干脆從結果中濾除。

            2.2 Purify的使用

            這里簡單介紹一下Purify在Windows和UNIX環境下的使用。

            在Windows中,只要運行Purify,填入需要分析的程序及參數就可。Purify會自動插入檢測代碼并顯示報告。報告的格式如下(來自[DEV205]):



            藍色的圖標代表一些運行的信息,比如開始和結束等。黃色是Purify給出的警告。通常UMR會作為警告列出。紅色則代表嚴重的錯誤。每一種相同的錯誤,尤其是在循環中的,會被集中在一起顯示,并且標明發生的次數。由每個錯誤的詳細信息,用戶可以知道相應的內存地址和源代碼的位置,并直接修改。另外用戶還可以設置不同的濾過器,用來隱藏暫時不關心的消息。

            在UNIX系統中,使用Purify需要重新編譯程序。通常的做法是修改Makefile中的編譯器變量。下面是用來編譯本文中程序的Makefile:


                    CC=purify gcc
                                    all: pplusdemo
                                    pplusdemo: pplusdemo.o
                                    $(CC) -o pplusdemo pplusdemo.o -lstdc++
                                    pplusdemo.o: pplusdemo.cpp
                                    $(CC) -g -c -w pplusdemo.cpp
                                    clean:
                                    -rm pplusdemo pplusdemo.o
                                    

            首先運行Purify安裝目錄下的purifyplus_setup.sh來設置環境變量,然后運行make重新編譯程序。需要指出的是,程序必須編譯成調試版本。在gcc中,也就是必須使用"-g"選項。在重新編譯的程序運行結束后,Purify會打印出一個分析報告。它的格式和含義與Windows平臺大同小異。

            下面是本文中的程序在Linux上Purify運行的結果:


                ****  Purify instrumented ./pplusdemo (pid 30669)  ****
                                    UMR: Uninitialized memory read:
                                    * This is occurring while in:
                                    strlen         [rtlib.o]
                                    std::basic_ostream< char,std::char_traits< char>> & std::operator
                                    <<<std::char_traits< char>>(std::basic_ostream< char,std::char_traits<
                                    char>> &, char const *) [libstdc++.so.5]
                                    main           [pplusdemo.cpp:7]
                                    __libc_start_main [libc.so.6]
                                    _start         [crt1.o]
                                    * Reading 1 byte from 0x80b45e0 in the heap.
                                    * Address 0x80b45e0 is at the beginning of a malloc'd block of 4 bytes.
                                    * This block was allocated from:
                                    malloc         [rtlib.o]
                                    operator new( unsigned) [libstdc++.so.5]
                                    operator new []( unsigned) [libstdc++.so.5]
                                    main           [pplusdemo.cpp:5]
                                    __libc_start_main [libc.so.6]
                                    _start         [crt1.o]
                                    ****  Purify instrumented ./pplusdemo (pid 30669)  ****
                                    ABW: Array bounds write:
                                    * This is occurring while in:
                                    strcpy         [rtlib.o]
                                    main           [pplusdemo.cpp:8]
                                    __libc_start_main [libc.so.6]
                                    _start         [crt1.o]
                                    * Writing 5 bytes to 0x80b45e0 in the heap (1 byte at 0x80b45e4 illegal).
                                    * Address 0x80b45e0 is at the beginning of a malloc'd block of 4 bytes.
                                    * This block was allocated from:
                                    malloc         [rtlib.o]
                                    operator new( unsigned) [libstdc++.so.5]
                                    operator new []( unsigned) [libstdc++.so.5]
                                    main           [pplusdemo.cpp:5]
                                    __libc_start_main [libc.so.6]
                                    _start         [crt1.o]
                                    ****  Purify instrumented ./pplusdemo (pid 30669)  ****
                                    ABR: Array bounds read:
                                    * This is occurring while in:
                                    strlen         [rtlib.o]
                                    std::basic_ostream< char,std::char_traits< char>> & std::operator
                                    <<<std::char_traits< char>>(std::basic_ostream< char,std::char_traits<
                                    char>> &, char const *) [libstdc++.so.5]
                                    main           [pplusdemo.cpp:9]
                                    __libc_start_main [libc.so.6]
                                    _start         [crt1.o]
                                    * Reading 5 bytes from 0x80b45e0 in the heap (1 byte at 0x80b45e4 illegal).
                                    * Address 0x80b45e0 is at the beginning of a malloc'd block of 4 bytes.
                                    * This block was allocated from:
                                    malloc         [rtlib.o]
                                    operator new( unsigned) [libstdc++.so.5]
                                    operator new []( unsigned) [libstdc++.so.5]
                                    main           [pplusdemo.cpp:5]
                                    __libc_start_main [libc.so.6]
                                    _start         [crt1.o]
                                    ****  Purify instrumented ./pplusdemo (pid 30669)  ****
                                    FMM: Freeing mismatched memory:
                                    * This is occurring while in:
                                    operator delete( void *) [rtlib.o]
                                    main           [pplusdemo.cpp:10]
                                    __libc_start_main [libc.so.6]
                                    _start         [crt1.o]
                                    * Attempting to free block at 0x80b45e0 in the heap.
                                    * Address 0x80b45e0 is at the beginning of a malloc'd block of 4 bytes.
                                    * This block was allocated from:
                                    malloc         [rtlib.o]
                                    operator new( unsigned) [libstdc++.so.5]
                                    operator new []( unsigned) [libstdc++.so.5]
                                    main           [pplusdemo.cpp:5]
                                    __libc_start_main [libc.so.6]
                                    _start         [crt1.o]
                                    * This block of memory was obtained using an allocation routine which is
                                    not compatible with the routine by which it is being freed.
                                    ****  Purify instrumented ./pplusdemo (pid 30669)  ****
                                    FMR: Free memory read:
                                    * This is occurring while in:
                                    main           [pplusdemo.cpp:11]
                                    __libc_start_main [libc.so.6]
                                    _start         [crt1.o]
                                    * Reading 1 byte from 0x80b45e0 in the heap.
                                    * Address 0x80b45e0 is at the beginning of a freed block of 4 bytes.
                                    * This block was allocated from:
                                    malloc         [rtlib.o]
                                    operator new( unsigned) [libstdc++.so.5]
                                    operator new []( unsigned) [libstdc++.so.5]
                                    main           [pplusdemo.cpp:5]
                                    __libc_start_main [libc.so.6]
                                    _start         [crt1.o]
                                    * There have been 0 frees since this block was freed from:
                                    free           [rtlib.o]
                                    _ZdLpV         [libstdc++.so.5]
                                    main           [pplusdemo.cpp:10]
                                    __libc_start_main [libc.so.6]
                                    _start         [crt1.o]
                                    ****  Purify instrumented ./pplusdemo (pid 30669)  ****
                                    FMW: Free memory write:
                                    * This is occurring while in:
                                    main           [pplusdemo.cpp:11]
                                    __libc_start_main [libc.so.6]
                                    _start         [crt1.o]
                                    * Writing 1 byte to 0x80b45e0 in the heap.
                                    * Address 0x80b45e0 is at the beginning of a freed block of 4 bytes.
                                    * This block was allocated from:
                                    malloc         [rtlib.o]
                                    operator new( unsigned) [libstdc++.so.5]
                                    operator new []( unsigned) [libstdc++.so.5]
                                    main           [pplusdemo.cpp:5]
                                    __libc_start_main [libc.so.6]
                                    _start         [crt1.o]
                                    * There have been 0 frees since this block was freed from:
                                    free           [rtlib.o]
                                    _ZdLpV         [libstdc++.so.5]
                                    main           [pplusdemo.cpp:10]
                                    __libc_start_main [libc.so.6]
                                    _start         [crt1.o]
                                    ****  Purify instrumented ./pplusdemo (pid 30669)  ****
                                    FUM: Freeing unallocated memory:
                                    * This is occurring while in:
                                    free           [rtlib.o]
                                    _ZdLpV         [libstdc++.so.5]
                                    main           [pplusdemo.cpp:12]
                                    __libc_start_main [libc.so.6]
                                    _start         [crt1.o]
                                    * Attempting to free block at 0x80b45e0 already freed.
                                    * This block was allocated from:
                                    malloc         [rtlib.o]
                                    operator new( unsigned) [libstdc++.so.5]
                                    operator new []( unsigned) [libstdc++.so.5]
                                    main           [pplusdemo.cpp:5]
                                    __libc_start_main [libc.so.6]
                                    _start         [crt1.o]
                                    * There have been 1 frees since this block was freed from:
                                    free           [rtlib.o]
                                    _ZdLpV         [libstdc++.so.5]
                                    main           [pplusdemo.cpp:10]
                                    __libc_start_main [libc.so.6]
                                    _start         [crt1.o]
                                    ****  Purify instrumented ./pplusdemo (pid 30669)  ****
                                    Current file descriptors in use: 5
                                    FIU: file descriptor 0: <stdin>
                                    FIU: file descriptor 1: <stdout>
                                    FIU: file descriptor 2: <stderr>
                                    FIU: file descriptor 26: <reserved for Purify internal use>
                                    FIU: file descriptor 27: <reserved for Purify internal use>
                                    ****  Purify instrumented ./pplusdemo (pid 30669)  ****
                                    Purify: Searching for all memory leaks...
                                    Memory leaked: 0 bytes (0%); potentially leaked: 0 bytes (0%)
                                    Purify Heap Analysis (combining suppressed and unsuppressed blocks)
                                    Blocks        Bytes
                                    Leaked          0            0
                                    Potentially Leaked          0            0
                                    In-Use          0            0
                                    ----------------------------------------
                                    Total Allocated          0            0
                                    ****  Purify instrumented ./pplusdemo (pid 30669)  ****
                                    * Program exited with status code 0.
                                    * 7 access errors, 7 total occurrences.
                                    * 0 bytes leaked.
                                    * 0 bytes potentially leaked.
                                    * Basic memory usage (including Purify overhead):
                                    290012 code
                                    152928 data/bss
                                    6816 heap (peak use)
                                    7800 stack
                                    

            我們對照程序可以發現Purify查出了程序中所有的錯誤。對于每個錯誤,她不但給出了源代碼的位置還指出這些內存最初分配的源代碼位置。這對于查找問題提供了很大幫助。對于程序12行的解釋,Purify將其認為是不匹配的內存釋放(FMM: Freeing mismatched memory),因為她認為這樣的釋放方式不符合嚴格的規定。

            Purify在其報告和文檔中使用了很多的縮寫,在此一并列出,以便讀者在使用時參考(來自[Purify]):



            2.3 Purify的一些特性

            這里簡單介紹一下Purify提供的幾個特性。有關這些特性的詳細信息,請查閱文檔[Purify]。

            • 觀察點(Watchpoint):通過在程序或者調試器中調用Purify 提供的觀察點函數,Purify可以報告有關被觀察對象的讀寫或其他操作。
            • 與Rational其他產品的集成:在Puify的用戶界面中可以方便地進入ClearCase和ClearQuest。Purify還可以和PureCoverage同時使用,對程序進行分析。
            • Purify的定制:無論是Purify報告中的消息,還是界面中的元素,都可以進行一定程度的定制。另外通過修改配置文件和調用Purify API,用戶還可以自動記錄運行日志,發送電子郵件等。
            • Purify提供的API:為了更好地把Purify融合到自動化測試的體系中,Purify提供了一系列的公開函數。用戶完全可以通過腳本的方式自動運行,記錄,和分析Purify。





            3.總結

            當使用C/C++進行開發時,采用良好的一致的編程規范是防止內存問題第一道也是最重要的措施。在此前提下,IBM Rational Purify作為一種運行時分析軟件可以很好地幫助您發現忽略的內存問題,或成為軟件自動測試中的一個重要組成部分。






            4.參考資料

            [C++Adv]
            [DEV205] Essentials of Rational PurifyPlus
            [Purify] IBM Rational PurifyPlus for Linux and UNIX Documentation



            關于作者

             

            蔡林,IBM 中國軟件開發中心軟件工程師,2004年獲得美國Baylor University計算機系碩士學位,同年加入IBM 中國軟件開發中心,從事Rational ClearQuest G11N的開發工作。

            posted @ 2009-05-25 23:36 董波 閱讀(981) | 評論 (0)編輯 收藏

            2009年5月24日 #

            【日記】最近干了點嘛?

                 摘要:         現在已經是大學生涯的最后階段了,回首過去的四年真是充滿感慨。由于畢業設計早早完事以至于現在略顯無聊,呵呵。但是一直都沒閑著,最近在研究內存管理方面的東西,參考了不少的書,有IBM出的那本《C++應用程序性能與優化》、《深入解析Windows操作系統》、《Windows核心編程》等等。目的就是想對Windows的內...  閱讀全文

            posted @ 2009-05-24 19:03 董波 閱讀(546) | 評論 (0)編輯 收藏

            2009年5月23日 #

            【轉帖】Visual C++中的日歷控件使用詳解

            文/劉濤  前言:

              控件在Visual C++編程學習中占據很重要的位置。筆者在國外英文網站上看到了這篇關于日歷控件學習的文章,雖然內容看似簡單,但讀完后感覺到還是學到了一些東西。感覺到原著作者對一些不常用的日歷控制的使用方法寫的介紹的很詳細,通俗易懂,于平淡之中顯神奇,是對日歷控件的"深度挖掘",對VC的初學者應該是很有幫助的,所以就將其翻譯過來介紹給國內讀者朋友。

              一、有關日歷控件的介紹

              Win32 API提供了一個顯示日期得當彩色日歷控件,日期的顯示模式是基于控制面板中的區域性設置或者說是依賴于用戶的操作系統。具體的日歷控件如下圖一所示:

            VisualC++中的日歷控件使用詳解
            圖一、日歷控件顯示效果

              這個常用的日歷控件的標題條包含兩個按鈕和兩個標簽,左邊的按鈕準許用戶單擊選擇前一個月份,左邊的標簽顯示當前選擇的月份,右邊的標簽顯示當前日期中的年份。右邊的按鈕是讓用戶選擇下一個月份。日歷控件可以配置成顯示多個月份,下圖是一具體的實例:

            VisualC++中的日歷控件使用詳解
            圖二、顯示多個月份的日歷控件

              如果要讓日歷控件顯示多個月份,按鈕的個數將通過前月或后月列表來增加或減少。例如,如果控件正在顯示4月或5月,這時用戶點擊了左邊的按鈕,控件將顯示3月或4月;如果用戶點擊了右邊的按鈕,控件將顯示5月和6月。此外,選擇當前年份中的任意一個月份,用戶可以點擊標題框中的月份名,這時候將顯示一個月份列表供用戶來選擇。具體如圖所示:

            VisualC++中的日歷控件使用詳解
            圖三、顯示月份列表

              如果要更改年份,用戶可以點擊年份標簽,這時候將顯示旋轉按鈕,用戶可以通過點擊旋轉按鈕的上下鍵來更改年份,也可以使用鍵盤上的上下箭頭來更改年份。

            VisualC++中的日歷控件使用詳解
            圖四、更改日歷控件的年份


            在標題條的下面,根據控制面板的格式顯示著星期的簡寫,在英語地區,每個星期的第一天通常是星期天。開發人員可以改變控件中的第一天設置。

              控件上,當前選擇的日期有一圓圈。用戶可以點擊欲選擇的日期來在控件上選擇一個日期。在大部分地區,日期以數字的形式顯現在一個白色背景上(這個背景顏色乃至控件上的任何顏色可以通過程序來改變)。默認的情況下,控件顯示一個橢圓圍繞的當前日期。使用標題條按鈕、月份和年份標簽,用戶可以更改日期。如果控件顯示的不是當前日期,用戶可以通過點擊控件底部顯示今天日期的標簽來使控件顯示今天的日期。(如果你是一個程序員,可以隱藏控件底部這個顯示今日日期的標簽)。

              二、創建日歷控件

              我們可以在窗口、對話框架、工具條及其他任何容器窗口中創建日歷控件。日歷控件對應著CmonthCalCtrl類,所以要動態創建一個日歷控件,需要聲明一個CmonthCalCtrl變量或指向CmonthCalCtrl的指針,代碼如下:

            // Exercise1Dlg.h : header file
            class CExercise1Dlg : public CDialog
            {
             // Construction
             public:
              CExercise1Dlg(CWnd* pParent = NULL); // standard constructor
             private:
              CMonthCalCtrl *ctlCalendar;
            };

              CmonthCalCtrl類象MFC中其他控件對應的類一樣,提供了一個Create()方法用來在容器窗口中動態創建日歷控件,代碼如下:

            CExercise1Dlg::CExercise1Dlg(CWnd* pParent /*=NULL*/)
            : CDialog(CExercise1Dlg::IDD, pParent)
            {
             //{{AFX_DATA_INIT(CExercise1Dlg)
             //}}AFX_DATA_INIT
             // Note that LoadIcon does not require a subsequent DestroyIcon in Win32
             m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
             ctlCalendar = new CMonthCalCtrl;
            }
            /////////////////////////////////////////////////////////////////////////////
            // CExercise1Dlg message handlers
            BOOL CExercise1Dlg::OnInitDialog()
            {
             CDialog::OnInitDialog();
             // Set the icon for this dialog. The framework does this automatically
             // when the application's main window is not a dialog
             SetIcon(m_hIcon, TRUE); // Set big icon
             SetIcon(m_hIcon, FALSE); // Set small icon
             // TODO: Add extra initialization here
             ctlCalendar->Create(WS_TABSTOP | WS_CHILD | WS_VISIBLE | WS_BORDER,CPoint(20, 20), this, 0x224);
             return TRUE; // return TRUE unless you set the focus to a control
            }

            三、日歷控件屬性操作

              在對話框或窗口中創建一個日歷控件后,它僅顯示當前的月份并僅僅只能顯示一個月份,這是因為,按照默認的設計,控件的長、寬、高只能容納一個月的日期,如果要顯示兩個月,就要增加控件的寬度(同樣的道理,也可以通過增加高度來顯示兩個月份)。

              作為一個可視化對象,日歷控件可以用不同的顏色來表現背景、星期日、標題條文本、標題條背景等。作為開發人員理所當然地可以通過程序來更換這些顏色,當然是要在不影響控件親合力的情況下。改變日歷控件的顏色,需要調用CMonthCalCtrl::SetColor() 方法,該方法的語法是:

            COLORREF SetColor(int nRegion, COLORREF ref);


              默認情況下,控件的標題條顯示藍色背景,如果要改變它,需要向nRegion參數傳遞MCSC_TITLEBK值,向ref參數傳遞你所要顯示的顏色。如果更改標題條上文本的顏色,需要向nRegion參數傳遞MCSC_TITLETEXT值。

            VisualC++中的日歷控件使用詳解(3)VisualC++中的日歷控件使用詳解(3)
            圖五、更改控件的標題條顏色


              上文說過,在標題條的下方顯示著星期日,在英語國家,一個星期的第一天是星期天,如果你想更改一個星期的第一天,可以調用函數SetFirstDayOfWeek(),它的語法是:

            BOOL SetFirstDayOfWeek(int iDay, int* lpnOld = NULL);


              第一個參數必須是對應的下列整數值:

            Value Weekday
            0 Monday
            1 Tuesday
            2 Wednesday
            3 Thursday
            4 Friday
            5 Saturday
            6 Sunday


              如果想要獲知日歷控件的星期天中具體哪一天設置為第一天,可以調用函數:GetFirstDayOfWeek(),它的語法是:

            int GetFirstDayOfWeek(BOOL* pbLocal = NULL) const;


              該函數返回一個整數值,它對應的含義與上個表格一致。

              星期日的名字使用的顏色與使用SetColor()函數傳遞MCSC_TITLETEXT時使用的顏色一致,在星期日的下面是一個水平分割線,默認情況下它該是黑色的,但這里它卻與選擇的日期一個顏色。在分割線下是日期列表,默認情況下背景是Windows默認的白色,如果要改變它,需要向nRegion參數傳遞MCSC_MONTHBK值,向ref參數傳遞你所要顯示的顏色。

              表示日期的數字顯示有兩種顏色,當前選擇的月份中的日期以黑色表示,如果要改變這種顏色,可以向需要向nRegion參數傳遞MCSC_TRAILINGTEXT值,向ref參數傳遞你所要顯示的顏色。

            VisualC++中的日歷控件使用詳解(3)VisualC++中的日歷控件使用詳解(3)
            圖六、更改日歷控件的日期顯示顏色

             

            分割線下的日期列表以兩種顏色顯示,為了規定當前月份中日期的顏色,可以向需要向nRegion參數傳遞MCSC_TEXT值,向ref參數傳遞你所要顯示的顏色。

              日歷控件習慣于用兩種形式來讓用戶了解當前的日期,一是在列表中以橢圓將當前日期圈起來,另一種方式是在底部以句子的形式顯示。在創建控件時,將"today"屬性設置為"NO"將不顯示今天的日期。

            VisualC++中的日歷控件使用詳解(4)
            圖七、不顯示"今日"標簽的日歷控件


              如上所述,默認情況下控件顯示今天日期,可以通過編程使用MCS_NOTODAY來隱藏這個標簽,代碼如下:

            BOOL CExercise1Dlg::OnInitDialog()
            {
             CDialog::OnInitDialog();

             // Set the icon for this dialog. The framework does this automatically
             // when the application's main window is not a dialog
             SetIcon(m_hIcon, TRUE); // Set big icon
             SetIcon(m_hIcon, FALSE); // Set small icon

             // TODO: Add extra initialization here

             ctlCalendar->Create(WS_TABSTOP | WS_CHILD |
               WS_VISIBLE | WS_BORDER | MCS_NOTODAY,
             CPoint(20, 20), this, 0x224);

             return TRUE; // return TRUE unless you set the focus to a control
            }


              我們注意到, 當前日期還被一個橢圓圈了起來,如果要將它隱藏起來,應該使用MCS_NOTODAYCIRCLE類型,代碼如下:

            BOOL CExercise1Dlg::OnInitDialog()
            {
             CDialog::OnInitDialog();
             // Set the icon for this dialog. The framework does this automatically
             // when the application's main window is not a dialog
             SetIcon(m_hIcon, TRUE); // Set big icon
             SetIcon(m_hIcon, FALSE); // Set small icon
             // TODO: Add extra initialization here
             ctlCalendar->Create(WS_TABSTOP | WS_CHILD |
               WS_VISIBLE | WS_BORDER |
               MCS_NOTODAYCIRCLE,
             CPoint(20, 20), this, 0x224);
             return TRUE; // return TRUE unless you set the focus to a control
            }


              為了獲取當前日歷控件中選擇的日期,可以使用方法:CMonthCalCtrl::GetCurSel(),該方法重載有3個版本,它們是:

            BOOL GetCurSel(COleDateTime& refDateTime) const;
            BOOL GetCurSel(CTime& refDateTime) const;
            BOOL GetCurSel(LPSYSTEMTIME pDateTime) const;


              這里有一個例子:

            void CExercise1Dlg::OnRetrieveBtn()
            {
             // TODO: Add your control notification handler code here
             UpdateData();
             CTime tme = this->m_dtpCurrent.GetCurrentTime();
             this->m_Result.Format("%s", tme.Format("%A, %B %d, %Y"));
             UpdateData(FALSE);
            }


            為了控制用戶是否可以選擇兩個以上的日期,在創建控件時可以相應地設置多項選擇屬性。例如,如果你想讓用戶在控件中選擇一定范圍的日期,可以將多項選擇屬性設置為真。為了動態設置多日期選擇,應用MCS_MULTISELECT屬性,代碼如下:

            BOOL CExercise1Dlg::OnInitDialog()
            {
             CDialog::OnInitDialog();
             // Set the icon for this dialog. The framework does this automatically
             // when the application's main window is not a dialog
             SetIcon(m_hIcon, TRUE); // Set big icon
             SetIcon(m_hIcon, FALSE); // Set small icon

             // TODO: Add extra initialization here

             ctlCalendar->Create(WS_TABSTOP | WS_CHILD |
                WS_VISIBLE | WS_BORDER |
                MCS_NOTODAYCIRCLE | MCS_MULTISELECT,
             CPoint(20, 20), this, 0x224);

             return TRUE; // return TRUE unless you set the focus to a control
            }


            VisualC++中的日歷控件使用詳解(5)
            圖八、顯示多選擇日期的日歷控件


              通過屬性設置,用戶可以在日歷控件中選擇多個日期,當然,也可以通過動態編程來選擇多個日期,這時,可以調用CMonthCalCtrl::SetSelRange()方法,它有三個不同的版本,語法是:

            BOOL SetSelRange(const COleDateTime& pMinRange, const COleDateTime& pMaxRange);
            BOOL SetSelRange(const CTime& pMinRange, const CTime& pMaxRange);
            BOOL SetSelRange(const LPSYSTEMTIME pMinRange, const LPSYSTEMTIME pMaxRange);


              如果想獲取一個日歷控件的可選擇范圍,可以調用CMonthCalCtrl::GetSelRange() 方法。

              為了控制用戶可選擇的日期范圍,可以調用CMonthCalCtrl::SetRange()方法,它也有三中不同的形式,分別是:

            BOOL SetRange(const COleDateTime* pMinRange, const COleDateTime* pMaxRange);
            BOOL SetRange(const CTime* pMinRange, const CTime* pMaxRange);
            BOOL SetRange(const LPSYSTEMTIME pMinRange, const LPSYSTEMTIME pMaxRange);


              第一個參數nMinRange是選擇范圍的開始日期,參數nMaxRange是可供選擇的最大日期。

             

            posted @ 2009-05-23 08:35 董波 閱讀(628) | 評論 (0)編輯 收藏

            2009年5月21日 #

            【原創】C++字符串分詞 -->C庫、boost.tokenizer、stlsoft.string_tokeniser討論

                 摘要: C++字符串分詞 董波 QQ:84638372 一 簡介     字符串分詞,即按照某一規則,將一個完整的字符串分割為更多的字段。在C庫當中,strtok/wcstok提供了類似的功能,C++標準庫兼容了C庫。C++的stringstream有類似的功能,boost.string_algorithm也有提供類似的泛型算法。另外在boost當中專門提供了boos...  閱讀全文

            posted @ 2009-05-21 13:43 董波 閱讀(8814) | 評論 (6)編輯 收藏

            2009年5月18日 #

            【原創】boost.shared_ptr的相等與等價

                 摘要: boost.shared_ptr的相等與等價 關于相等和不等 template<class T, class U> inline bool operator==(shared_ptr<T> const & a, shared_ptr<U> const & b) {     return a.get() == ...  閱讀全文

            posted @ 2009-05-18 11:12 董波 閱讀(2280) | 評論 (0)編輯 收藏

            【原創】boost.compressed_pair源碼剖析

                 摘要: boost.compressed_pair源碼剖析 意義 當compressed_pair的某一個模板參數為一個空類的時候將對其進行“空基類優化”,這樣可以使得compressed_pair占用的空間比std::pair的更小。 參考如下代碼: #include <iostream> using namespace std;   #inc...  閱讀全文

            posted @ 2009-05-18 11:09 董波 閱讀(1213) | 評論 (0)編輯 收藏

            僅列出標題  
            2021国内久久精品| 久久精品国产一区二区电影| 久久精品免费全国观看国产| 亚洲伊人久久综合影院| 久久亚洲日韩看片无码| 亚洲国产另类久久久精品 | 久久精品成人免费看| 亚洲一本综合久久| 久久笫一福利免费导航 | 久久国产高清字幕中文| 久久精品无码专区免费| 中文字幕久久波多野结衣av| 久久香蕉国产线看观看99| 一本色综合久久| 99久久人人爽亚洲精品美女| 久久天天躁夜夜躁狠狠| 久久免费国产精品一区二区| 久久人人爽人人爽人人片AV不 | 久久精品亚洲一区二区三区浴池| 狠狠色丁香久久综合婷婷| 要久久爱在线免费观看| 久久99精品综合国产首页| 中文字幕无码久久精品青草| 99热精品久久只有精品| 色综合久久无码中文字幕| 欧美久久久久久| 色综合久久久久综合99| 一本色道久久88加勒比—综合| 亚洲AV乱码久久精品蜜桃| 久久只这里是精品66| 久久国产一片免费观看| 国产精品久久久久久福利漫画| 热re99久久精品国99热| 日本五月天婷久久网站| 女人高潮久久久叫人喷水| 久久久久久毛片免费看| 久久国产成人| 一本大道久久东京热无码AV | 久久精品国产半推半就| 国产三级久久久精品麻豆三级| 新狼窝色AV性久久久久久|