青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

曠野的呼聲

路漫漫其修遠(yuǎn)兮 吾將上下而求索

常用鏈接

統(tǒng)計(jì)

最新評(píng)論

2010年1月5日 #

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

地址在這里

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


#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;
}

 這才是我經(jīng)常活動(dòng)的家

posted @ 2010-01-05 16:42 董波 閱讀(657) | 評(píng)論 (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 是帶有翻譯的英文, 看來這篇文章是原始作者的大作了。轉(zhuǎn)帖過來

柏林噪聲(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.
很多人在他們的程序中使用隨機(jī)數(shù)生成器去創(chuàng)造不可預(yù)測(cè),使物體的行為和運(yùn)動(dòng)表現(xiàn)的更加自然,或者生成紋理。隨機(jī)數(shù)生成器當(dāng)然是有他們的用途的,但是它們似乎過于苛刻。這篇文章將會(huì)展示一個(gè)用途十分廣泛的功能,甚至其用途比我想到的還要廣泛,其結(jié)果可以輕易的適合你的需求。

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.
如果你觀察自然界中很多事物,你會(huì)注意到它們是分形的。它們有著很多層次細(xì)節(jié)。最平常的例子是山峰輪廓。它包含著高度上的很大變化(山峰),中等變化(丘陵),小的變化(礫石),微小變化(石頭)...你可以繼續(xù)想象。觀察幾乎所有事物:片狀分布于田間草,海中的波浪,螞蟻的運(yùn)動(dòng)方式,樹枝的運(yùn)動(dòng),大理石的花紋,風(fēng)。所有這些現(xiàn)象表現(xiàn)出了同一種的大小的變化形式。柏林噪聲函數(shù)通過直接添加一定范圍內(nèi),不同比例的噪聲函數(shù)來重現(xiàn)這種現(xiàn)象。

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

Introduction To Noise Functions
噪聲函數(shù)介紹

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.
一個(gè)噪聲函數(shù)基本上是一個(gè)種子隨機(jī)發(fā)生器。它需要一個(gè)整數(shù)作為參數(shù),然后返回根據(jù)這個(gè)參數(shù)返回一個(gè)隨機(jī)數(shù)。如果你兩次都傳同一個(gè)參數(shù)進(jìn)來,它就會(huì)產(chǎn)生兩次相同的數(shù)。這條規(guī)律非常重要,否則柏林函數(shù)只是生成一堆垃圾。




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


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.
通過在值之間平滑的插值,我們定義了一個(gè)帶有一個(gè)非整參數(shù)的連續(xù)函數(shù)。我們將會(huì)在后面的內(nèi)容中討論多種插值方式

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.
當(dāng)我們準(zhǔn)備深入之前,讓我定義下什么是振幅(amplitude)和頻率(frequency)。如果你學(xué)過物理,你可能遇到過在正玄波中振幅(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.
正玄波
正玄波的波長(zhǎng)(wavelength)是兩個(gè)波峰只間的距離。振幅是此波的高度。頻率我們定義為 1/波長(zhǎng)(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.
噪聲波
圖中這個(gè)噪聲波的例子中,紅點(diǎn)表示定義沿著在函數(shù)維上的隨機(jī)值。在這種情況下,振幅是這個(gè)函數(shù)的最大值與最小值的差值。波長(zhǎng)(wavelength)是兩個(gè)紅點(diǎn)之間的距離。同樣的頻率(frequency)定義為1/波長(zhǎng)(wavelength).

Creating the Perlin Noise Function
創(chuàng)建柏林噪聲函數(shù)

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.
現(xiàn)在,如果你使用很多平滑函數(shù),分別擁有各種各樣的頻率和振幅,你可以把他們疊加在一起來創(chuàng)建一個(gè)漂亮的噪聲函數(shù)。這個(gè)就是柏林噪聲函數(shù)。

Take the following Noise Functions
使用以下的噪聲函數(shù)



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


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.
你能發(fā)現(xiàn)這個(gè)函數(shù)擁有大的,中的和小的變化。你甚至可以它已經(jīng)有點(diǎn)像山的輪廓了。事實(shí)上很多電腦生成地形景觀也是使用了這種方法,當(dāng)然那使用的是2D的噪聲,我們將過一下來研究這個(gè)。

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

Some noise functions are created in 2D
一些2D的噪聲函數(shù)




Adding all these functions together produces a noisy pattern.
把這些函數(shù)疊加起來產(chǎn)生的噪聲樣式。



Persistence
持續(xù)度

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.
當(dāng)你把噪聲函數(shù)疊加的時(shí)候,你可能想了解每次具體使用了什么振幅和頻率。上面一維的例子對(duì)于每個(gè)連續(xù)疊加的噪聲函數(shù)使用了兩倍的頻率和二分之一倍的振幅。這個(gè)太普通了,事實(shí)上太普通,以至于很多人甚至從來都沒有考慮過使用其他什么。盡管如此,你可以通過在每步使用其他的頻率和振幅來創(chuàng)建不同特征的柏林噪聲函數(shù)。例如,為了創(chuàng)建一個(gè)平滑滾動(dòng)的丘陵,你可以使用大的振幅和小的頻率的柏林噪聲函數(shù),同時(shí)小的振幅和高的頻率,你可以創(chuàng)建一個(gè)平地,另外要?jiǎng)?chuàng)建非常顛簸的平面,應(yīng)該選擇小的振幅和低的頻率。

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:
為了讓這些更簡(jiǎn)單易懂,同時(shí)為了避免重復(fù)振幅和頻率這兩個(gè)詞,我們用一個(gè)數(shù)來表示每個(gè)頻率下的振幅,這個(gè)數(shù)就是持續(xù)度(Persistence)。這里的詞和它的真實(shí)意義有些歧異。這個(gè)術(shù)語原本是Mandelbrot提出的,他是發(fā)現(xiàn)分形現(xiàn)象的人中的一個(gè)。他定義噪聲擁有大量的高頻率將體現(xiàn)出低的持續(xù)度。我的朋友Matt也想出了持續(xù)度的概念,但是是通過另外一種方式定義它的。誠然,我更喜歡Matt的定義方式。對(duì)不起了,Mandelbrot. 所以我們這樣定義持續(xù)度(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個(gè)被疊加的噪聲函數(shù)。為了展示柏林函數(shù)在輸出上持續(xù)度的表現(xiàn)效果,請(qǐng)看下下面的圖表。他們展示了疊加的每個(gè)組成部分,持續(xù)度的效果和最終的柏林函數(shù)。



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.
每個(gè)你所疊加的噪聲函數(shù)就是一個(gè)倍頻。因?yàn)槊恳粋€(gè)噪聲函數(shù)是上一個(gè)的兩倍頻率。在音樂上,倍頻也有著這項(xiàng)屬性。

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.
具體多少倍頻你疊加在一起,這完全取決于你。你可以疊加很多也可以很少。盡管如此,還是讓我給你一些建議吧。如果你正使用柏林噪聲函數(shù)在屏幕上渲染圖象的話,如果倍頻頻率太高將會(huì)使縮成一個(gè)點(diǎn)以至于不能顯示,這就是因?yàn)槟闫聊坏姆直媛什粔颉R恍┌亓衷肼暫瘮?shù)的實(shí)現(xiàn)會(huì)自動(dòng)疊加噪聲函數(shù)直到達(dá)到屏幕分辨率的極限。

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).
當(dāng)振幅變的很小的時(shí)候,也應(yīng)該明智的停止再疊加噪聲函數(shù)。屆時(shí)當(dāng)發(fā)生依靠持續(xù)度的等級(jí),柏林函數(shù)整體的振幅和屏幕的分辨率(翻譯的爛)。

Making your noise functions
創(chuàng)造你的噪聲函數(shù)

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.
我們需要什么樣的噪聲函數(shù)?好,基本上就是一個(gè)隨機(jī)數(shù)發(fā)生器。盡管如此,它不像你在程序中遇到的那中每次調(diào)用它都返回不同的隨機(jī)數(shù)的隨機(jī)函數(shù),這些噪聲函數(shù)生成一個(gè)隨機(jī)數(shù)是通過一個(gè)或者多個(gè)參數(shù)計(jì)算而來。例如,每次你傳入一個(gè)相同的數(shù)到噪聲函數(shù)里,它將每次也返回相同的隨機(jī)數(shù)。但是如果傳入一個(gè)不同的數(shù),那么它又將返回一個(gè)不同的數(shù),

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.
好,我對(duì)隨機(jī)數(shù)生成器并不懂太多,所以我去找了一些,這里我找到了一個(gè),好象很好用。它返回一個(gè)浮點(diǎn)數(shù),范圍是-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
現(xiàn)在,你將要需要幾個(gè)不同的隨機(jī)數(shù)生成器,所以我建議把上面的代碼復(fù)制幾個(gè)拷貝,然后稍微修改下里面的參數(shù)。那些可怕的數(shù)字都是質(zhì)數(shù),所以你可以改成其他差不多大小的質(zhì)數(shù)(讓我想起了 hash key生成),為了讓你輕松的找的隨機(jī)數(shù),我已經(jīng)寫了一個(gè)小程序來為你列出質(zhì)數(shù)。你只用輸入一個(gè)起始值和一個(gè)結(jié)束值,它找到所有在兩值之間的質(zhì)數(shù)。源代碼也提供,所以你可以輕松的包含到你自己的程序中來生成隨機(jī)的質(zhì)數(shù).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.
當(dāng)創(chuàng)建了你的噪聲函數(shù),你將需要平滑下他的返回值。再次,你可以選擇任何你喜歡的方式,但是有一些效果更好。一個(gè)標(biāo)準(zhǔn)的插值函數(shù)需要三個(gè)輸入,a 和 b, 需要在a和b之間進(jìn)行插值,還有x,它取值范圍是0到1。插值函數(shù)返回a到b之間取決與x的一個(gè)值。當(dāng)x等于0,它返回a,當(dāng)x等于1時(shí),它返回b。當(dāng)x 是0到1之間時(shí),它將返回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.
看起來很齷齪的,像那些每個(gè)人用來生成地形的廉價(jià)'plasmas'一樣,它是一個(gè)簡(jiǎn)單的算法,如果你想實(shí)時(shí)的使用柏林噪聲函數(shù),這種插值方式是一個(gè)選擇。

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.
這個(gè)方法線性插值生成了更平滑的曲線。它當(dāng)然有著更好的效果,如果你愿意稍微損失點(diǎn)速度的話。

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.
這個(gè)方法的確是生成了非常平滑的結(jié)果,但是你付出的代價(jià)就是速度。老實(shí)說,我不那么確定它能給你比余玄插值好很多的效果,但是如果你無論如何要使用它的話,它有一點(diǎn)點(diǎn)的復(fù)雜,所以這里請(qǐng)注意,之前,插值函數(shù)只需要三個(gè)參數(shù),但是立方插值需要五個(gè),取代了a和b,現(xiàn)在你需要v0,v1,v2,v3,x和以前一樣也需要。


這些是:
v0 = a 前面一點(diǎn)
v1 = a 點(diǎn)
v2 = b 點(diǎn)
v3 = b 后面一點(diǎn)


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.
除了插值,你也可以平滑噪聲函數(shù)的輸出來使它看起來不那么隨機(jī),和讓2D和3D的版本少一點(diǎn)方塊。平滑的結(jié)果和你所想的差不多,只要是寫過平滑過濾或者火焰算法的人都應(yīng)該相當(dāng)熟悉此過程。相比在一個(gè)單獨(dú)的坐標(biāo)上取得噪聲值,你可以取平均的噪聲值,和它臨近的值。如果你不清楚這個(gè),可以看看下面的偽代碼。

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.
在右面(這里看下面),你可以看見一個(gè)小的圖展示了不同平滑函數(shù)的區(qū)別,和同樣的一個(gè)噪聲但未進(jìn)行平滑處理。你可以看見平滑函數(shù),從來都沒有到底那個(gè)未平滑函數(shù)的極限值,并且頻率顯得只有大約一半。那里有小點(diǎn)平滑一維的噪聲,只有這一個(gè)效果。平滑過程在二維和三維中,顯得更有用處,那就是它減少了噪聲大方塊。不幸的是它也降低了一點(diǎn)對(duì)比度。你讓它越平滑,這個(gè)噪聲就會(huì)越平坦。



1-dimensional Smooth Noise
一維噪聲函數(shù)
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
二維噪聲函數(shù)
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.
既然你知道了全部這些,現(xiàn)在是時(shí)候把他們組合在一起了,你將學(xué)會(huì)并創(chuàng)建一個(gè)柏林函數(shù)。記住這知識(shí)幾個(gè)插值的噪聲函數(shù)疊加在一起。所以柏林函數(shù)只是一個(gè)函數(shù)。你傳入一個(gè)或多個(gè)參數(shù),然后它返回一個(gè)數(shù)給你。所以很簡(jiǎn)單,一維的柏林函數(shù)是這樣。

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.
柏林函數(shù)重要的部分是那個(gè)循環(huán)。每次循環(huán)跌代疊加另一個(gè)兩倍頻率的倍頻。每次跌代調(diào)用一個(gè)不同的噪聲函數(shù),稱做Noisei。當(dāng)然,你并不需要真的寫為每個(gè)倍頻很多噪聲函數(shù),偽代碼中好象只是建議這么做。既然所有的噪聲函數(shù)實(shí)際上都是相同的,除了那三個(gè)大質(zhì)數(shù)不同除外,你可以使用同樣的代碼,只是每個(gè)代碼改用不同的質(zhì)數(shù)。

1-dimensional Perlin Noise Pseudo code
一維柏林噪聲函數(shù)偽代碼
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:
現(xiàn)在可以輕松的使用同樣的代碼創(chuàng)建二維或者多維的柏林噪聲函數(shù)了:

2-dimensional Perlin Noise Pseudocode
二維柏林噪聲函數(shù)偽代碼
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博客,轉(zhuǎn)載請(qǐng)標(biāo)明出處:http://blog.csdn.net/anywn1314/archive/2007/10/15/1825765.aspx

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

2009年8月28日 #

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

相對(duì)而言,對(duì)比較小,而且多的文件打包是很有意義的,這也是為什么越來越多的游戲?qū)β曇糍Y源不打包的原因。

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

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

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

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

2009年6月10日 #

【原創(chuàng)】游戲中的聲音資源打包

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

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

2009年5月25日 #

【轉(zhuǎn)帖】Rational Purify 使用及分析實(shí)例

Rational Purify 使用及分析實(shí)例

developerWorks

級(jí)別: 初級(jí)

蔡 林, IBM 中國(guó)軟件開發(fā)中心軟件工程師

2006 年 2 月 23 日

本文介紹了 IBM Rational Purify的基本概念和在不同操作系統(tǒng)中使用Purify對(duì)C/C++源程序中存在的內(nèi)存問題進(jìn)行勘察和分析,并且提供了有關(guān)的實(shí)例以便讀者在實(shí)際操作中作為參考。

簡(jiǎn)介

本文介紹了IBM Rational Purify的基本概念和在不同操作系統(tǒng)中使用Purify對(duì)C/C++源程序中存在的內(nèi)存問題進(jìn)行勘察和分析,并且提供了有關(guān)的實(shí)例以便讀者在實(shí)際操作中作為參考。






1.內(nèi)存問題的原因及分類

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

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

1.1 內(nèi)存解剖

一個(gè)典型的C++內(nèi)存布局如下圖所示:



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

1.2 內(nèi)存訪問錯(cuò)誤

相對(duì)用戶使用的語言,動(dòng)態(tài)內(nèi)存的申請(qǐng)一般由malloc/new來完成,釋放由free/delete完成。基本的原則可以總結(jié)為:一對(duì)一,不混用。也就是說一個(gè)malloc必須對(duì)應(yīng)一且唯一的free;new對(duì)應(yīng)一且唯一的delete; malloc不能和delete, new不能和free對(duì)應(yīng)。另外在C++中要注意delete和delete[]的區(qū)別。delete用來釋放單元變量,delete[]用來釋放數(shù)組等集聚變量。有關(guān)這方面的詳細(xì)信息可以參考[C++Adv]。

我們可以將內(nèi)存訪問錯(cuò)誤大致分成以下幾類:數(shù)組越界讀或?qū)憽⒃L問未初始化內(nèi)存、訪問已經(jīng)釋放的內(nèi)存和重復(fù)釋放內(nèi)存或釋放非法內(nèi)存。

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


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行分配內(nèi)存時(shí),忽略了字符串終止符"\0"所占空間導(dǎo)致了第8行的數(shù)組越界寫(Array Bounds Write)和第9行的數(shù)組越界讀(Array Bounds Read); 在第7行,打印尚未賦值的str2將產(chǎn)生訪問未初始化內(nèi)存錯(cuò)誤(Uninitialized Memory Read);在第11行使用已經(jīng)釋放的變量將導(dǎo)致釋放內(nèi)存讀和寫錯(cuò)誤(Freed Memory Read and Freed Memory Write);最后由于str3和str2所指的是同一片內(nèi)存,第12行又一次釋放了已經(jīng)被釋放的空間 (Free Freed Memory)。

這個(gè)包含許多錯(cuò)誤的程序可以編譯連接,而且可以在很多平臺(tái)上運(yùn)行。但是這些錯(cuò)誤就像定時(shí)炸彈,會(huì)在特殊配置下觸發(fā),造成不可預(yù)見的錯(cuò)誤。這就是內(nèi)存錯(cuò)誤難以發(fā)現(xiàn)的一個(gè)主要原因。

1.3 內(nèi)存使用錯(cuò)誤

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






2.Purify的原理及使用

IBM Rational PurifyPlus是一組程序運(yùn)行時(shí)的分析軟件。她包括了程序性能瓶頸分析軟件Quantify, 程序覆蓋面分析軟件PureCoverage,和本文的主角:程序運(yùn)行錯(cuò)誤分析軟件Purify。Purify可以發(fā)現(xiàn)程序運(yùn)行時(shí)的內(nèi)存訪問,內(nèi)存泄漏和其他難以發(fā)現(xiàn)的問題。

同時(shí)她也是市場(chǎng)上唯一支持多種平臺(tái)的類似工具,并且可以和很多主流開發(fā)工具集成。Purify可以檢查應(yīng)用的每一個(gè)模塊,甚至可以查出復(fù)雜的多線程或進(jìn)程應(yīng)用中的錯(cuò)誤。另外她不僅可以檢查C/C++,還可以對(duì)Java或.NET中的內(nèi)存泄漏問題給出報(bào)告。

2.1 Purify的原理

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

對(duì)于所有程序中使用的動(dòng)態(tài)內(nèi)存,Purify將它們按照狀態(tài)進(jìn)行歸類。這可以由下圖來說明(來自[DEV205]):



參見本文中以上給出的代碼,在程序第5行執(zhí)行后,str2處于黃色狀態(tài)。當(dāng)在第7行進(jìn)行讀的時(shí)候,系統(tǒng)就會(huì)報(bào)告一個(gè)訪問未初始化內(nèi)存錯(cuò)誤(Uninitialized Memory Read)。因?yàn)橹挥性诰G色狀態(tài)下,內(nèi)存才可以被合法訪問。

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

2.2 Purify的使用

這里簡(jiǎn)單介紹一下Purify在Windows和UNIX環(huán)境下的使用。

在Windows中,只要運(yùn)行Purify,填入需要分析的程序及參數(shù)就可。Purify會(huì)自動(dòng)插入檢測(cè)代碼并顯示報(bào)告。報(bào)告的格式如下(來自[DEV205]):



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

在UNIX系統(tǒng)中,使用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
                        

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

下面是本文中的程序在Linux上Purify運(yùn)行的結(jié)果:


    ****  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
                        

我們對(duì)照程序可以發(fā)現(xiàn)Purify查出了程序中所有的錯(cuò)誤。對(duì)于每個(gè)錯(cuò)誤,她不但給出了源代碼的位置還指出這些內(nèi)存最初分配的源代碼位置。這對(duì)于查找問題提供了很大幫助。對(duì)于程序12行的解釋,Purify將其認(rèn)為是不匹配的內(nèi)存釋放(FMM: Freeing mismatched memory),因?yàn)樗J(rèn)為這樣的釋放方式不符合嚴(yán)格的規(guī)定。

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



2.3 Purify的一些特性

這里簡(jiǎn)單介紹一下Purify提供的幾個(gè)特性。有關(guān)這些特性的詳細(xì)信息,請(qǐng)查閱文檔[Purify]。

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





3.總結(jié)

當(dāng)使用C/C++進(jìn)行開發(fā)時(shí),采用良好的一致的編程規(guī)范是防止內(nèi)存問題第一道也是最重要的措施。在此前提下,IBM Rational Purify作為一種運(yùn)行時(shí)分析軟件可以很好地幫助您發(fā)現(xiàn)忽略的內(nèi)存問題,或成為軟件自動(dòng)測(cè)試中的一個(gè)重要組成部分。






4.參考資料

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



關(guān)于作者

 

蔡林,IBM 中國(guó)軟件開發(fā)中心軟件工程師,2004年獲得美國(guó)Baylor University計(jì)算機(jī)系碩士學(xué)位,同年加入IBM 中國(guó)軟件開發(fā)中心,從事Rational ClearQuest G11N的開發(fā)工作。

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

2009年5月24日 #

【日記】最近干了點(diǎn)嘛?

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

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

2009年5月23日 #

【轉(zhuǎn)帖】Visual C++中的日歷控件使用詳解

文/劉濤  前言:

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

  一、有關(guān)日歷控件的介紹

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

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

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

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

  如果要讓日歷控件顯示多個(gè)月份,按鈕的個(gè)數(shù)將通過前月或后月列表來增加或減少。例如,如果控件正在顯示4月或5月,這時(shí)用戶點(diǎn)擊了左邊的按鈕,控件將顯示3月或4月;如果用戶點(diǎn)擊了右邊的按鈕,控件將顯示5月和6月。此外,選擇當(dāng)前年份中的任意一個(gè)月份,用戶可以點(diǎn)擊標(biāo)題框中的月份名,這時(shí)候?qū)@示一個(gè)月份列表供用戶來選擇。具體如圖所示:

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

  如果要更改年份,用戶可以點(diǎn)擊年份標(biāo)簽,這時(shí)候?qū)@示旋轉(zhuǎn)按鈕,用戶可以通過點(diǎn)擊旋轉(zhuǎn)按鈕的上下鍵來更改年份,也可以使用鍵盤上的上下箭頭來更改年份。

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


在標(biāo)題條的下面,根據(jù)控制面板的格式顯示著星期的簡(jiǎn)寫,在英語地區(qū),每個(gè)星期的第一天通常是星期天。開發(fā)人員可以改變控件中的第一天設(shè)置。

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

  二、創(chuàng)建日歷控件

  我們可以在窗口、對(duì)話框架、工具條及其他任何容器窗口中創(chuàng)建日歷控件。日歷控件對(duì)應(yīng)著CmonthCalCtrl類,所以要?jiǎng)討B(tài)創(chuàng)建一個(gè)日歷控件,需要聲明一個(gè)CmonthCalCtrl變量或指向CmonthCalCtrl的指針,代碼如下:

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

  CmonthCalCtrl類象MFC中其他控件對(duì)應(yīng)的類一樣,提供了一個(gè)Create()方法用來在容器窗口中動(dòng)態(tài)創(chuàng)建日歷控件,代碼如下:

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
}

三、日歷控件屬性操作

  在對(duì)話框或窗口中創(chuàng)建一個(gè)日歷控件后,它僅顯示當(dāng)前的月份并僅僅只能顯示一個(gè)月份,這是因?yàn)椋凑漳J(rèn)的設(shè)計(jì),控件的長(zhǎng)、寬、高只能容納一個(gè)月的日期,如果要顯示兩個(gè)月,就要增加控件的寬度(同樣的道理,也可以通過增加高度來顯示兩個(gè)月份)。

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

COLORREF SetColor(int nRegion, COLORREF ref);


  默認(rèn)情況下,控件的標(biāo)題條顯示藍(lán)色背景,如果要改變它,需要向nRegion參數(shù)傳遞MCSC_TITLEBK值,向ref參數(shù)傳遞你所要顯示的顏色。如果更改標(biāo)題條上文本的顏色,需要向nRegion參數(shù)傳遞MCSC_TITLETEXT值。

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


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

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


  第一個(gè)參數(shù)必須是對(duì)應(yīng)的下列整數(shù)值:

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


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

int GetFirstDayOfWeek(BOOL* pbLocal = NULL) const;


  該函數(shù)返回一個(gè)整數(shù)值,它對(duì)應(yīng)的含義與上個(gè)表格一致。

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

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

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

 

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

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

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


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

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
}


  我們注意到, 當(dāng)前日期還被一個(gè)橢圓圈了起來,如果要將它隱藏起來,應(yīng)該使用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
}


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

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


  這里有一個(gè)例子:

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);
}


為了控制用戶是否可以選擇兩個(gè)以上的日期,在創(chuàng)建控件時(shí)可以相應(yīng)地設(shè)置多項(xiàng)選擇屬性。例如,如果你想讓用戶在控件中選擇一定范圍的日期,可以將多項(xiàng)選擇屬性設(shè)置為真。為了動(dòng)態(tài)設(shè)置多日期選擇,應(yīng)用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)
圖八、顯示多選擇日期的日歷控件


  通過屬性設(shè)置,用戶可以在日歷控件中選擇多個(gè)日期,當(dāng)然,也可以通過動(dòng)態(tài)編程來選擇多個(gè)日期,這時(shí),可以調(diào)用CMonthCalCtrl::SetSelRange()方法,它有三個(gè)不同的版本,語法是:

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


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

  為了控制用戶可選擇的日期范圍,可以調(diào)用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);


  第一個(gè)參數(shù)nMinRange是選擇范圍的開始日期,參數(shù)nMaxRange是可供選擇的最大日期。

 

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

2009年5月21日 #

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

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

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

2009年5月18日 #

【原創(chuàng)】boost.shared_ptr的相等與等價(jià)

     摘要: boost.shared_ptr的相等與等價(jià) 關(guān)于相等和不等 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 董波 閱讀(2315) | 評(píng)論 (0)編輯 收藏

【原創(chuàng)】boost.compressed_pair源碼剖析

     摘要: boost.compressed_pair源碼剖析 意義 當(dāng)compressed_pair的某一個(gè)模板參數(shù)為一個(gè)空類的時(shí)候?qū)?duì)其進(jìn)行“空基類優(yōu)化”,這樣可以使得compressed_pair占用的空間比std::pair的更小。 參考如下代碼: #include <iostream> using namespace std;   #inc...  閱讀全文

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

僅列出標(biāo)題  
青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <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>
            亚洲第一精品久久忘忧草社区| 精品51国产黑色丝袜高跟鞋| 中文在线一区| 一本综合久久| 国产精品久久久久久久久久久久久久 | 一个色综合导航| 欧美午夜精品理论片a级按摩| 亚洲午夜激情网站| 亚洲欧美国产三级| 激情综合久久| 亚洲精品在线二区| 国产伦精品一区二区三区四区免费| 欧美影院视频| 蜜臀va亚洲va欧美va天堂| 亚洲理论在线观看| 亚洲在线免费观看| 亚洲大胆美女视频| 亚洲美女免费视频| 国产资源精品在线观看| 欧美激情久久久久| 欧美日韩专区在线| 欧美一级久久久| 久久综合色影院| 亚洲一区二区三区四区中文 | 日韩午夜在线视频| 国产欧美一区二区三区沐欲| 欧美xart系列高清| 国产精品久久久久久久久久久久久| 久久综合影音| 欧美日韩国产限制| 久久免费一区| 国产精品久久久久77777| 美女诱惑一区| 国产精品亚洲综合久久| 亚洲经典自拍| 狠狠综合久久av一区二区小说| 亚洲欧洲一区二区天堂久久| 国内久久精品视频| 亚洲午夜一区二区三区| 亚洲日本在线视频观看| 欧美一二三区精品| 在线视频亚洲欧美| 欧美va亚洲va香蕉在线| 久久视频这里只有精品| 国产精品视频网| 99国产精品久久久久久久| 亚洲韩日在线| 久久亚洲国产精品日日av夜夜| 香蕉成人啪国产精品视频综合网| 欧美福利视频在线观看| 乱人伦精品视频在线观看| 国产欧美日韩在线观看| 一区二区激情视频| 夜夜嗨av一区二区三区四区| 老鸭窝91久久精品色噜噜导演| 久久精品中文字幕一区二区三区| 欧美视频精品在线| 亚洲精品美女在线| 日韩亚洲不卡在线| 欧美国产视频在线| 亚洲国产成人精品女人久久久| 红桃视频亚洲| 久久久久国产成人精品亚洲午夜| 欧美中在线观看| 国产欧美在线看| 午夜精品短视频| 久久久999精品免费| 国产亚洲精品高潮| 欧美一区亚洲二区| 久久先锋影音| 亚洲国产欧美久久| 欧美国产精品va在线观看| 亚洲国产综合在线| 一本到12不卡视频在线dvd| 欧美日韩理论| 亚洲影院免费观看| 久久久久国色av免费观看性色| 国内视频一区| 蜜臀99久久精品久久久久久软件| 亚洲福利视频专区| 一本色道久久99精品综合 | 久久精品日韩一区二区三区| 久久最新视频| 亚洲毛片在线观看| 国产精品v欧美精品∨日韩| 亚洲图片欧洲图片日韩av| 欧美一区二区在线| 影音先锋久久资源网| 欧美成年视频| 亚洲素人在线| 麻豆免费精品视频| 一区二区高清视频| 国产美女诱惑一区二区| 久久久久国内| aa亚洲婷婷| 久久亚洲精品中文字幕冲田杏梨| 亚洲片区在线| 国产精品无码永久免费888| 久久精品中文字幕一区二区三区| 亚洲大片一区二区三区| 亚洲欧美日韩视频一区| 狠狠色综合日日| 欧美日本中文字幕| 久久国产精品99久久久久久老狼 | 蜜臀av在线播放一区二区三区| 一本大道久久a久久综合婷婷 | 欧美黄免费看| 亚洲欧美综合另类中字| 亚洲国产日韩综合一区| 欧美影院在线播放| 一本一本久久a久久精品综合妖精| 国产精品亚洲成人| 欧美精品情趣视频| 久久精品成人欧美大片古装| 一区二区欧美在线观看| 欧美高清影院| 午夜激情亚洲| 欧美一级视频精品观看| 欧美激情一二区| 亚洲在线视频| 亚洲免费激情| 一区免费观看视频| 国产精品亚洲片夜色在线| 欧美不卡高清| 久久精品99| 午夜精品久久久久久久99黑人| 欧美黄色影院| 免费一级欧美在线大片| 欧美影院视频| 午夜欧美精品久久久久久久| 99国产精品久久久久老师| 亚洲高清网站| 在线视频成人| 伊人色综合久久天天五月婷| 国产亚洲精品久久久| 国产免费成人| 国产精品久久福利| 国产精品久久久久免费a∨| 欧美精品一区二区三区视频| 欧美xxx在线观看| 美日韩免费视频| 蜜桃精品久久久久久久免费影院| 欧美在线播放| 久久精品久久99精品久久| 欧美在线视频一区| 欧美一区二区在线| 欧美诱惑福利视频| 久久精品国产亚洲精品| 亚洲欧美日韩视频一区| 久久精品72免费观看| 国产欧美精品在线播放| 欧美手机在线| 欧美福利视频在线| 欧美日韩18| 国产精品激情电影| 国产日韩欧美成人| 国产亚洲一区二区三区| 好吊妞这里只有精品| 亚洲国产电影| 一个色综合av| 新67194成人永久网站| 久久国产精品久久久久久电车| 久久久www免费人成黑人精品 | 亚洲第一精品夜夜躁人人爽| 亚洲国产视频直播| 日韩天堂av| 香蕉精品999视频一区二区| 久久久久国产精品麻豆ai换脸 | 91久久国产综合久久蜜月精品| 国产欧美婷婷中文| 最新国产乱人伦偷精品免费网站| 欧美国产在线电影| 亚洲国产婷婷香蕉久久久久久99| 亚洲黄色毛片| 一区二区三区精品在线| 亚洲中字黄色| 久久免费视频观看| 欧美日韩成人在线播放| 国产日韩欧美精品在线| 亚洲三级免费电影| 午夜精品久久| 欧美激情一二区| 亚洲香蕉网站| 美女露胸一区二区三区| 国产精品网曝门| 亚洲黄一区二区三区| 欧美亚洲三区| 亚洲黄网站在线观看| 午夜免费在线观看精品视频| 美女精品在线观看| 国产亚洲毛片在线| 99精品欧美一区二区蜜桃免费| 久久精品国产一区二区三区| 亚洲人成小说网站色在线| 久久成人精品| 欧美另类69精品久久久久9999| 国产精品久久久久毛片大屁完整版| 极品av少妇一区二区| 午夜精品国产更新| 亚洲三级免费电影|