?? waveobject.asm
字號:
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 水波效果公用子程序
; by 羅云彬,http://asm.yeah.net,luoyunbin@sina.com
; V 1.0.041019 --- 初始版本
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 在源代碼中只需要 include WaveObject.asm
; 然后按以下步驟調用即可:
;********************************************************************
; 1、創建水波對象:
; 要對一個窗口進行繪畫,首先要創建一個水波對象(本函數申請一些緩沖區)
; invoke _WaveInit,lpWaveObject,hWnd,hBmp,dwTime,dwType
; lpWaveObject --> 指向一個空的 WAVE_OBJECT 結構
; hWnd --> 要繪畫水波效果的窗口,渲染后的圖片將畫到窗口的客戶區中
; hBmp --> 背景圖片,繪畫的范圍大小同背景圖片大小
; dwTime --> 刷新的時間間隔(毫秒),建議值:10~30
; dwType --> =0 表示圓形水波,=1表示橢圓型水波(用于透視效果)
; 返回值:eax = 0(成功,對象被初始化),eax = 1(失敗)
;********************************************************************
; 2、如果 _WaveInit 函數返回成功,則對象被初始化,將對象傳給下列各種函數
; 可以實現各種效果,下面函數中的 lpWaveObject 參數指向在 _WaveInit 函數
; 中初始化的 WAVE_OBJECT 結構
;
; ◎ 在指定位置“扔石頭”,激起水波
; invoke _WaveDropStone,lpWaveObject,dwPosX,dwPosY,dwStoneSize,dwStoneWeight
; dwPosX,dwPosY --> 扔下石頭的位置
; dwStoneSize --> 石頭的大小,即初始點的大小,建議值:0~5
; dwStoneWeight --> 石頭的重量,決定了波最后擴散的范圍大小,建議值:10~1000
;
; ◎ 自動顯示特效
; invoke _WaveEffect,lpWaveObject,dwEffectType,dwParam1,dwParam2,dwParam3
; dwParam1,dwParam2,dwParam3 --> 效果參數,對不同的特效類型參數含義不同
; dwEffectType --> 特效類型
; 0 --> 關閉特效
; 1 --> 下雨,Param1=密集速度(0最密,越大越稀疏),建議值:0~30
; Param2=最大雨點直徑,建議值:0~5
; Param3=最大雨點重量,建議值:50~250
; 2 --> 汽艇,Param1=速度(0最慢,越大越快),建議值:0~8
; Param2=船大小,建議值:0~4
; Param3=水波擴散的范圍,建議值:100~500
; 3 --> 風浪,Param1=密度(越大越密),建議值:50~300
; Param2=大小,建議值:2~5
; Param3=能量,建議值:5~10
;
; ◎ 窗口客戶區強制更新(用于在窗口的WM_PAINT消息中強制更新客戶端)
; .if uMsg == WM_PAINT
; invoke BeginPaint,hWnd,addr @stPs
; mov @hDc,eax
; invoke _WaveUpdateFrame,lpWaveObject,eax,TRUE
; invoke EndPaint,hWnd,addr @stPs
; xor eax,eax
; ret
;********************************************************************
; 3、釋放水波對象:
; 使用完畢后,必須將水波對象釋放(本函數將釋放申請的緩沖區內存等資源)
; invoke _WaveFree,lpWaveObject
; lpWaveObject --> 指向 WAVE_OBJECT 結構
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 實現上的細節說明:
;
; 1、 水波的特征:
; ◎ 擴散:每一點的波會擴散到其四周的位置中
; ◎ 衰減:每次擴散會損失少量能量(否則水波會永不停止的震蕩下去)
;
; 2、 為了保存兩個時刻中的能量分步圖,對象中定義2個緩沖區Wave1和Wave2
; (保存在lpWave1和lpWave2指向的緩沖區內),Wave1為當前數據,Wave2為
; 上一幀的數據,每次渲染時將根據上面的2個特征,由Wave1的數據計算出新
; 能量分別圖后,保存到Wave2中,然后調換Wave1和Wave2,這時Wave1仍是最
; 新的數據。
; 計算的方法為,某個點的能量=點四周的上次能量的平均值 * 衰減系數
; 取四周的平均值表現了擴展特征,乘以衰減系數表現了衰減特征。
; 這部分代碼在 _WaveSpread 子程序中實現。
;
; 3、 對象在 lpDIBitsSource 中保存了原始位圖的數據,每次渲染時,由原始
; 位圖的數據根據Wave1中保存的能量分步數據產生新的位圖。從視覺上看,
; 某個點的能量越大(水波越大),則光線折射出越遠處的場景。
; 算法為:對于點(x,y),在Wave1中找出該點,計算出相鄰點的波能差
; (Dx和Dy兩個數據),則新位圖像素(x,y)=原始位圖像素(x+Dx,y+Dy),
; 該算法表現了能量大小影響了像素折射的偏移大小。
; 這部分代碼在 _WaveRender 子程序中實現。
;
; 4、 扔石頭的算法很好理解,即將Wave1中的某個點的能量值置為非0值,數值
; 越大,表示扔下的石頭的能量越大。石頭比較大,則將該點四周的點全部
; 置為非0值。
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
;
;
;
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
ifndef WAVEOBJ_INC
WAVEOBJ_INC equ 1
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
F_WO_ACTIVE equ 0001h
F_WO_NEED_UPDATE equ 0002h
F_WO_EFFECT equ 0004h
F_WO_ELLIPSE equ 0008h
WAVE_OBJECT struct
hWnd dd ?
dwFlag dd ? ; 見 F_WO_xxx 組合
;********************************************************************
hDcRender dd ?
hBmpRender dd ?
lpDIBitsSource dd ? ; 原始像素數據
lpDIBitsRender dd ? ; 用于顯示到屏幕的像素數據
lpWave1 dd ? ; 水波能量數據緩沖1
lpWave2 dd ? ; 水波能量數據緩沖2
;********************************************************************
dwBmpWidth dd ?
dwBmpHeight dd ?
dwDIByteWidth dd ? ; = (dwBmpWidth * 3 + 3) and ~3
dwWaveByteWidth dd ? ; = dwBmpWidth * 4
dwRandom dd ?
;********************************************************************
; 特效參數
;********************************************************************
dwEffectType dd ?
dwEffectParam1 dd ?
dwEffectParam2 dd ?
dwEffectParam3 dd ?
;********************************************************************
; 用于行船特效
;********************************************************************
dwEff2X dd ?
dwEff2Y dd ?
dwEff2XAdd dd ?
dwEff2YAdd dd ?
dwEff2Flip dd ?
;********************************************************************
stBmpInfo BITMAPINFO <>
WAVE_OBJECT ends
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
.code
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 隨機數產生子程序
; 輸入:要產生的隨機數的最大值,輸出:隨機數
; 根據:
; 1. 數學公式 Rnd=(Rnd*I+J) mod K 循環回帶生成 K 次以內不重復的
; 偽隨機數,但K,I,J必須為素數
; 2. 2^(2n-1)-1 必定為素數(即2的奇數次方減1)
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
_WaveRandom16 proc _lpWaveObject
mov ebx,_lpWaveObject
assume ebx:ptr WAVE_OBJECT
push edx
push ecx
mov eax,[ebx].dwRandom
mov ecx,32768-1 ;2^15-1
mul ecx
add eax,2048-1 ;2^11-1
adc edx,0
mov ecx,2147483647 ;2^31-1
div ecx
mov eax,[ebx].dwRandom
mov [ebx].dwRandom,edx
and eax,0000ffffh
pop ecx
pop edx
ret
_WaveRandom16 endp
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
_WaveRandom proc uses ebx ecx edx _lpWaveObject,_dwMax
invoke _WaveRandom16,_lpWaveObject
mov edx,eax
invoke _WaveRandom16,_lpWaveObject
shl eax,16
or ax,dx
mov ecx,_dwMax
or ecx,ecx
jz @F
xor edx,edx
div ecx
mov eax,edx
@@:
ret
_WaveRandom endp
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 波能擴散
; 算法:
; Wave2(x,y) = (Wave1(x+1,y)+Wave1(x-1,y)+Wave1(x,y+1)+Wave1(x,y-1))/2-Wave2(x,y)
; Wave2(x,y) = Wave2(x,y) - Wave2(x,y) >> 5
; xchg Wave1,Wave2
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
_WaveSpread proc _lpWaveObject
pushad
mov ebx,_lpWaveObject
assume ebx:ptr WAVE_OBJECT
;********************************************************************
test [ebx].dwFlag,F_WO_ACTIVE
jz _Ret
mov esi,[ebx].lpWave1
mov edi,[ebx].lpWave2
mov ecx,[ebx].dwBmpWidth
mov eax,[ebx].dwBmpHeight
dec eax
mul ecx
;********************************************************************
; ebx = width
; ecx = i,eax = max
;********************************************************************
.while ecx < eax
push eax
.if [ebx].dwFlag & F_WO_ELLIPSE
mov edx,[esi+ecx*4-1*4]
add edx,[esi+ecx*4+1*4]
add edx,[esi+ecx*4-2*4]
add edx,[esi+ecx*4+2*4]
lea edx,[edx+edx*2]
add edx,[esi+ecx*4-3*4]
add edx,[esi+ecx*4-3*4]
add edx,[esi+ecx*4+3*4]
add edx,[esi+ecx*4+3*4]
lea eax,[esi+ecx*4]
sub eax,[ebx].dwWaveByteWidth
mov eax,[eax]
shl eax,3
add edx,eax
lea eax,[esi+ecx*4]
add eax,[ebx].dwWaveByteWidth
mov eax,[eax]
shl eax,3
add edx,eax
sar edx,4
sub edx,[edi+ecx*4]
mov eax,edx
sar eax,5
sub edx,eax
mov [edi+ecx*4],edx
.else
mov edx,[esi+ecx*4-1*4]
add edx,[esi+ecx*4+1*4]
lea eax,[esi+ecx*4]
sub eax,[ebx].dwWaveByteWidth
add edx,[eax]
lea eax,[esi+ecx*4]
add eax,[ebx].dwWaveByteWidth
add edx,[eax]
sar edx,1
sub edx,[edi+ecx*4]
mov eax,edx
sar eax,5
sub edx,eax
mov [edi+ecx*4],edx
.endif
pop eax
inc ecx
.endw
mov [ebx].lpWave1,edi
mov [ebx].lpWave2,esi
_Ret:
;********************************************************************
assume ebx:nothing
popad
ret
_WaveSpread endp
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; esi -> edi, ecx = line width
; return = (4*Pixel(x,y)+3*Pixel(x-1,y)+3*Pixel(x+1,y)+3*Pixel(x,y+1)+3*Pixel(x,y-1))/16
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
_WaveGetPixel:
movzx eax,byte ptr [esi]
shl eax,2
movzx edx,byte ptr [esi+3]
lea edx,[edx+2*edx]
add eax,edx
movzx edx,byte ptr [esi-3]
lea edx,[edx+2*edx]
add eax,edx
movzx edx,byte ptr [esi+ecx]
lea edx,[edx+2*edx]
add eax,edx
mov edx,esi
sub edx,ecx
movzx edx,byte ptr [edx]
lea edx,[edx+2*edx]
add eax,edx
shr eax,4
mov [edi],al
inc esi
inc edi
ret
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 渲染子程序,將新的幀數據渲染到 lpDIBitsRender 中
; 算法:
; posx = Wave1(x-1,y)-Wave1(x+1,y)+x
; posy = Wave1(x,y-1)-Wave1(x,y+1)+y
; SourceBmp(x,y) = DestBmp(posx,posy)
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
_WaveRender proc _lpWaveObject
local @dwPosX,@dwPosY,@dwPtrSource,@dwFlag
pushad
xor eax,eax
mov @dwFlag,eax
mov ebx,_lpWaveObject
assume ebx:ptr WAVE_OBJECT
test [ebx].dwFlag,F_WO_ACTIVE
jz _Ret
or [ebx].dwFlag,F_WO_NEED_UPDATE
mov esi,[ebx].lpWave1
mov edi,[ebx].dwWaveByteWidth ; edi = 像素指針
xor ecx,ecx
inc ecx ; ecx=i -- i=1; i<height; i++
_Loop1:
xor edx,edx ; edx=j -- j=0; j<width; j++
_Loop2:
push edx
;********************************************************************
; PosY=i+像素上1能量-像素下1能量
; PosX=j+像素左1能量-像素右1能量
;********************************************************************
mov eax,edi
sub eax,[ebx].dwWaveByteWidth
mov eax,[esi+eax]
mov @dwPosY,eax
mov eax,[ebx].dwWaveByteWidth
lea eax,[edi+eax]
mov eax,[esi+eax]
sub @dwPosY,eax
add @dwPosY,ecx
mov eax,[esi+edi-4]
sub eax,[esi+edi+4]
add eax,edx ;@dwPosX = eax
mov @dwPosX,eax
cmp eax,0
jl _Continue
cmp eax,[ebx].dwBmpWidth
jge _Continue
mov eax,@dwPosY
cmp eax,0
jl _Continue
cmp eax,[ebx].dwBmpHeight
jge _Continue
;********************************************************************
; ptrSource = dwPosY * dwDIByteWidth + dwPosX * 3
; ptrDest = i * dwDIByteWidth + j * 3
;********************************************************************
mov eax,@dwPosX
lea eax,[eax+eax*2]
mov @dwPosX,eax
push edx
mov eax,@dwPosY
mul [ebx].dwDIByteWidth
add eax,@dwPosX
mov @dwPtrSource,eax
mov eax,ecx
mul [ebx].dwDIByteWidth
pop edx
lea edx,[edx+edx*2]
add eax,edx ;@dwPtrDest = eax
;********************************************************************
; 渲染像素 [ptrDest] = 原始像素 [ptrSource]
;********************************************************************
pushad
mov ecx,@dwPtrSource
mov esi,[ebx].lpDIBitsSource
mov edi,[ebx].lpDIBitsRender
lea esi,[esi+ecx]
lea edi,[edi+eax]
.if ecx != eax
or @dwFlag,1 ;如果存在源像素和目標像素不同,則表示還在活動狀態
mov ecx,[ebx].dwDIByteWidth
call _WaveGetPixel
call _WaveGetPixel
call _WaveGetPixel
.else
cld
movsw
movsb
.endif
popad
;********************************************************************
; 繼續循環
;********************************************************************
_Continue:
pop edx
inc edx
add edi,4 ; 像素++
cmp edx,[ebx].dwBmpWidth
jb _Loop2
inc ecx
mov eax,[ebx].dwBmpHeight
dec eax
cmp ecx,eax
jb _Loop1
;********************************************************************
; 將渲染的像素數據拷貝到 hDc 中
;********************************************************************
invoke SetDIBits,[ebx].hDcRender,[ebx].hBmpRender,0,[ebx].dwBmpHeight,\
[ebx].lpDIBitsRender,addr [ebx].stBmpInfo,DIB_RGB_COLORS
.if ! @dwFlag
and [ebx].dwFlag,not F_WO_ACTIVE
.endif
_Ret:
;********************************************************************
assume ebx:nothing
popad
ret
_WaveRender endp
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
_WaveUpdateFrame proc _lpWaveObject,_hDc,_bIfForce
pushad
mov ebx,_lpWaveObject
assume ebx:ptr WAVE_OBJECT
cmp _bIfForce,0
jnz @F
.if [ebx].dwFlag & F_WO_NEED_UPDATE
@@:
invoke BitBlt,_hDc,0,0,[ebx].dwBmpWidth,[ebx].dwBmpHeight,\
[ebx].hDcRender,0,0,SRCCOPY
and [ebx].dwFlag,not F_WO_NEED_UPDATE
.endif
assume ebx:nothing
popad
ret
_WaveUpdateFrame endp
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 扔一塊石頭
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
_WaveDropStone proc _lpWaveObject,_dwX,_dwY,_dwSize,_dwWeight
local @dwMaxX,@dwMaxY
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -