I use double buffer but still it flicker. Can it posible because bitblt is slow? I did saw about set thread priority function or something, can it maybe solve the problem?
What is the function name? Set thread priority? I forgot. Last time I use that function my computer smells like burn. But im not sure.
[attachment deleted by admin]
I think the problem is what used to be called "tearing". It is normally caused by the buffer update and screen refresh being out of sync. This page explains the problem and demonstrates a method of avoiding it, without having your code waste time in a polling loop. If you manage to create an ASM version of this code, I would be interested in seeing it. I saved the link so I could experiment with it, but I have never found the time to do so:
http://www.codeproject.com/gdi/tearingfreedrawing.asp
MSDN: SetPriorityClass (http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dllproc/base/setpriorityclass.asp)
Sure. After I finish the problem I will send the source. And also what function do you suggest for this? WaitForVerticalRetrace? But it is not available on GDI function.
This demonstrates a minimal solution that I think should work for most systems.
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
include \masm32\include\masm32rt.inc
include \masm32\include\ddraw.inc
includelib \masm32\lib\ddraw.lib
DD_OK EQU 0
DDO_GetScanLine EQU 64
DDERR_INVALIDPARAMS EQU E_INVALIDARG
DDERR_UNSUPPORTED EQU E_NOTIMPL
DDERR_INVALIDOBJECT EQU ((1 shl 31) or (876h shl 16) or ( 130 ))
DDERR_VERTICALBLANKINPROGRESS EQU ((1 shl 31)or(876h shl 16)or(537))
DDGetScanLine PROTO scanLine:DWORD
WaitForVerticalBlank PROTO
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
.data
lpdd_1 dd 0
scanLine dd 0
maxScanLine dd 0
vbStart dd 0
vbEnd dd 0
temp dd 0
.code
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
start:
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
; ------------------------------------
; Create a default DirectDraw object.
; ------------------------------------
invoke DirectDrawCreate,NULL,ADDR lpdd_1,NULL
.IF (eax)
print "DirectDrawCreate failed",13,10
jmp fini
.ENDIF
; -----------------------------------------------------------
; Make sure DDGetScanLine doesn't have any obvious problems.
; -----------------------------------------------------------
invoke DDGetScanLine, ADDR scanLine
.IF (eax != DD_OK)
SWITCH (eax)
CASE DDERR_INVALIDPARAMS
print "DDERR_INVALIDPARAMS",13,10
CASE DDERR_UNSUPPORTED
print "DDERR_UNSUPPORTED",13,10
CASE DDERR_INVALIDOBJECT
print "DDERR_INVALIDOBJECT",13,10
ENDSW
jmp fini
.ENDIF
; ---------------------------------------------------
; Set HIGH_PRIORITY_CLASS to miminize interruptions.
; ---------------------------------------------------
invoke GetCurrentProcess
invoke SetPriorityClass, eax, HIGH_PRIORITY_CLASS
; ----------------------------------------------------
; Determine the maximum scan line, which will be the
; value of the scan line counter at the bottom of the
; top border, immediately above the first visible
; scan line (scan line 0).
; ----------------------------------------------------
mov ebx, 100000
.WHILE (ebx)
invoke DDGetScanLine, ADDR scanLine
.IF (eax == DD_OK)
mov eax, scanLine
.IF (eax > maxScanLine)
mov maxScanLine, eax
.ENDIF
.ENDIF
dec ebx
.ENDW
print "maximum scan line = "
print ustr$(maxScanLine),13,10
; ----------------------------------------
; Determine the scan lines where vertical
; blank starts and ends.
; ----------------------------------------
invoke DDGetScanLine, ADDR scanLine
.WHILE (scanLine)
invoke DDGetScanLine, ADDR scanLine
.ENDW
.WHILE (TRUE)
invoke DDGetScanLine, ADDR scanLine
.IF (eax != DDERR_VERTICALBLANKINPROGRESS)
m2m vbStart, scanLine
inc vbStart
.ELSE
.WHILE (eax == DDERR_VERTICALBLANKINPROGRESS)
invoke DDGetScanLine, ADDR scanLine
.ENDW
m2m vbEnd, scanLine
.BREAK
.ENDIF
.ENDW
print "vertical blank start = "
print ustr$(vbStart),13,10
print "vertical blank end = "
print ustr$(vbEnd),13,10
; ----------------------------------------
; Determine the approximate refresh rate.
; ----------------------------------------
invoke GetTickCount
mov ebx, eax
.WHILE (eax == ebx)
invoke GetTickCount
.ENDW
mov temp, eax
mov ebx, 200
.WHILE (ebx)
invoke WaitForVerticalBlank
dec ebx
.ENDW
invoke GetTickCount
sub eax, temp
mov temp, eax
fld8 200000.0
fild temp
fdiv
fistp temp
print chr$("approximate refresh rate = ")
print ustr$(temp),'Hz',13,10
invoke GetCurrentProcess
invoke SetPriorityClass, eax, NORMAL_PRIORITY_CLASS
fini:
mov eax, input(13,10,"Press enter to exit...")
exit
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
DDGetScanLine proc lpScanLine:DWORD
push lpScanLine
push lpdd_1
mov eax, lpdd_1
mov eax, [eax]
call DWORD PTR[eax+DDO_GetScanLine]
ret
DDGetScanLine endp
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
WaitForVerticalBlank proc
LOCAL localScanLine:DWORD
invoke DDGetScanLine, ADDR localScanLine
; -------------------------------
; Wait until not vertical blank.
; -------------------------------
.WHILE (eax == DDERR_VERTICALBLANKINPROGRESS)
invoke DDGetScanLine, ADDR localScanLine
.ENDW
; ---------------------------
; Wait until vertical blank.
; ---------------------------
.WHILE (eax != DDERR_VERTICALBLANKINPROGRESS)
invoke DDGetScanLine, ADDR localScanLine
.ENDW
ret
WaitForVerticalBlank endp
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
end start
Hai. Please test this, I heard it was crashes. Is this crashes on your computer?
http://www.geocities.com/realvampire2001/Contoh_program.zip
Both work fine for me on AMD XP SP2. :)
Both crash for me, Win2k :eek
Both work OK for me: P3, Windows 2000 SP4, default version of DirectX (8.1), default drivers for Matrox G200.
Oops, my bad, didn't extract the sound! :lol
Both work fine now :U
Thank you very much for testing it. I will upload the source soon.
Brixton:
So in Win2k if the music did not extracted it crash. Thanks for let me know about it.
Quote from: Farabi on June 20, 2005, 12:11:41 AMBrixton:
So in Win2k if the music did not extracted it crash. Thanks for let me know about it.
Yes. They both crashed at slightly different stages though. :eek
About the source I cannot post it. The size is above 256 Kbytes.
Here is the old source. Its disneat I hope you can understand it. Its free for you to modify or recreate it for commercial or non commercial purpose.
[attachment deleted by admin]
Here is a screen shot
(http://www.geocities.com/realvampire2001/Clipboard.jpg)
I cannot send the code rigth now because it still under development. It still big.
Here is the very basic function to made a circle. Unfortunately FPU is very slow. Im still find another way to make it fast and this is what I know to make it fast.
*Note: The clock information on this code is wrong*
If this code
push eax
fld dword ptr[esp]
pop eax
fimul delta
fistp r_cos
replaced with this code
; xor edx,edx
; mov ecx,delta
; mul ecx
; mov ecx,1000
; div ecx
; mov eax,r_cos
I can save time until 15 times on 1.7 GHz celeron machine. I tried it but it crashed. I dont know what causing it. When I debug it with ollydbg, it stop at this function.
GetSin proc uses esi deg:dword ; 3 Clock cycle
mov esi,SCTbl ; 1 Clock cycle
mov ecx,deg ; 1 Clock cycle
mov eax,dword ptr[esi+ecx*4] ; 1 Clock cycle
ret
GetSin endp
Ecx register on GetSin procedure point to a wrong place and reported access violation. Maybe someone here understand and can solve this?
Phase1 proc uses esi ; 28.8 Kbyte needed
LOCAL deg,sin,cos,tan:dword
invoke GlobalAlloc,LMEM_DISCARDABLE,28800+14400 + 16*10000 +768
invoke GlobalLock,eax
mov SCTbl,eax
mov esi,eax ; 1 Clock cycle
xor ecx,ecx ; 1 Clock cycle
mov deg,ecx ; 1 Clock cycle
mov edx,3600 ; 1 Clock cycle
shl edx,2 ; 2 Clock cycle
@@:
finit ; 17 Clock cycle
pushad
invoke Deg2Rad,deg ; 104 Clock cycle
popad
fsincos ; 365 Clock cycle
fstp sin ; 8 Clock cycle
fstp cos ; 8 Clock cycle
; push 1000
; fimul dword ptr[esp]
; fistp sin
; pop eax
; push 1000
; fimul dword ptr[esp]
; fistp cos
; pop eax
mov eax,sin ; 1 Clock cycle
mov dword ptr[esi],eax ; 1 Clock cycle
mov eax,cos ; 1 Clock cycle
mov dword ptr[esi+edx],eax ; 1 Clock cycle
add deg,1 ; 3 Clock cycle
add esi,4 ; 1 Clock cycle
add ecx,4 ; 1 Clock cycle
cmp deg,3600 ; 2 Clock cycle
jl @b ; 3 Clock cycle
; 513 Clock cycle Each loop
; 1846800 Clock cycle total loop
; 1846806 Clock cycle
mov esi,SCTbl
add esi,28800
;Tan
mov edx,3600 ; 1 Clock cycle
shl edx,2 ; 2 Clock cycle
xor ecx,ecx
mov deg,ecx
@@:
finit ; 17 Clock cycle
pushad
invoke Deg2Rad,deg ; 104 Clock cycle
popad
fptan ; 273 Clock cycle
fstp tan
; push 1000
; fimul dword ptr[esp]
; fistp tan
; pop eax
;
push tan
pop [esi]
add deg,1 ; 3 Clock cycle
add esi,4 ; 1 Clock cycle
add ecx,4 ; 1 Clock cycle
cmp deg,3600 ; 2 Clock cycle
jl @b ; 3 Clock cycle
mov esi,SCTbl
add esi,28800+14400
mov Line_Table,esi
mov eax,16*10000
mov nLLimit,eax
mov nLPtr,0
add esi,eax
mov SCR_TBL,esi
mov ecx,768
xor eax,eax
xor edx,edx
@@:
mov [esi+edx*4],eax
add eax,1024
dec ecx
jnz @b
ret
Phase1 endp
UMGetPosRound proc uses esi delta:dword,deg:dword ; 138 Clock cycle
LOCAL r_sin,r_cos:dword
cmp deg,3600
jl @f
sub deg,3600
@@:
invoke GetSin,deg
push eax
fld dword ptr[esp]
pop eax
fimul delta
fistp r_sin
; xor edx,edx
; mov ecx,delta
; mul ecx
; mov ecx,1000
; div ecx
; mov eax,r_sin
invoke GetCos,deg
push eax
fld dword ptr[esp]
pop eax
fimul delta
fistp r_cos
; xor edx,edx
; mov ecx,delta
; mul ecx
; mov ecx,1000
; div ecx
; mov eax,r_cos
mov edx,r_sin
mov eax,r_cos
ret
UMGetPosRound endp
GetSin proc uses esi deg:dword ; 3 Clock cycle
mov esi,SCTbl ; 1 Clock cycle
mov ecx,deg ; 1 Clock cycle
mov eax,dword ptr[esi+ecx*4] ; 1 Clock cycle
ret
GetSin endp
GetCos proc uses esi deg:dword ; 4 Clock cycle
mov esi,SCTbl ; 1 Clock cycle
add esi,14400 ; 1 Clock cycle
mov ecx,deg ; 1 Clock cycle
mov eax,dword ptr[esi+ecx*4] ; 1 Clock cycle
ret
GetCos endp
GetTan proc uses esi deg:dword ; 4 Clock cycle
mov esi,SCTbl ; 1 Clock cycle
add esi,28800 ; 1 Clock cycle
mov ecx,deg ; 1 Clock cycle
mov eax,dword ptr[esi+ecx*4] ; 1 Clock cycle
ret
GetTan endp
[attachment deleted by admin]
why not use bresenhams circlealgo instead?
Hi Farabi, i dont know if i am able to help you!
Here are some topics about the case. I am trying to understand the problem itself, so
1. sin(x + 360) = sin(x), cos(x + 360) = cos(x) , tan(x + 360) = tan(x)
2. Here, why «add ecx, 4 ; 1 Clock cycle» ?
add deg,1 ; 3 Clock cycle
add esi,4 ; 1 Clock cycle
add ecx,4 ; 1 Clock cycle
cmp deg,3600 ; 2 Clock cycle
jl @b ; 3 Clock cycle
ECX is not used between @@ and jl @B (i thk it is not used, but ...):
@@: finit
...
cmp deg, 3600
jl @B
;-------------------------------------------------------
3. mov edx, 3600
shl edx, 2
could be
mov edx, 14 400
;--------------------------------------------------------
4. The proc Phase1 create a table of functions SIN(deg), COS(deg) and
TAN(deg) ( deg is the angle in degrees ) in this way:
SCTbl dd sin 0 <- Address = SCTbl SCTblSin
dd sin 1
...
dd sin 3 599 ; 3 600 dwords = 14 400 bytes
;
dd cos 0 <- Address = SCTbl + 14 400 SCTblCos
dd cos 1
...
dd cos 3 599
;
dd tan 0 <- Address = SCTbl + 28 800 SCTblTan
dd tan 1
...
dd tan 3 599
;
<- Address = SCTbl + 43 200
where you have
mov SCTbl, eax
would be
mov SCTblSin, eax
add eax, 14 400
mov SCTblCos, eax
add eax, 14 400
mov SCTblTan, eax
implying
GetSin proc uses esi deg:dword
mov esi, SCTblSin
mov ecx,deg
mov eax,dword ptr[esi+ecx*4]
ret
GetSin endp
;...................................................
GetCos proc uses esi deg:dword
mov esi, SCTblCos
mov ecx,deg
mov eax,dword ptr[esi+ecx*4]
ret
GetCos endp
;...............................................
GetTan proc uses esi deg:dword
mov esi, SCTblTan
mov ecx,deg
mov eax,dword ptr[esi+ecx*4]
ret
GetTan endp
;-------------------------------------------------------------------------------
5. If this code
push eax
fld dword ptr[esp]
pop eax
fimul delta
fistp r_cos
is replaced with this code
xor edx, edx
mov ecx, delta
mul ecx
mov ecx, 1000
div ecx
mov eax, r_cos
the var «r_cos» is not defined . The value is not valid. The proc would be:
UMGetPosRound proc uses esi delta:dword,deg:dword ; 138 Clock cycle
LOCAL r_sin,r_cos:dword
cmp deg,3600
jl @f
sub deg,3600
;
; Get Sin[deg] in EAX
; -------------------
@@: invoke GetSin, deg
; calculate r_sin
xor edx,edx
mov ecx,delta
mul ecx
mov ecx,1000
div ecx
mov eax,r_sin ; <= ERROR => change mov r_sin , eax
; push eax ; r_sin
;
; Get Cos[deg] in EAX
; -------------------
invoke GetCos, deg
; calculate r_cos
xor edx,edx
mov ecx,delta
mul ecx
mov ecx,1000
div ecx
mov eax,r_cos ; <= ERROR => change mov r_cos, eax
;
; Return r_sin and r_cos
; ----------------------
; pop edx ; r_sin
mov edx, r_sin
mov eax, r_cos
ret
UMGetPosRound endp
If we use push eax and pop edx then we dont need mov edx, r_sin and mov eax, r_cos.
Is this right ? That's all.
stay well
ポ ゼ チ
Quote from: daydreamer on June 20, 2005, 04:56:29 PM
why not use bresenhams circlealgo instead?
Because I dont understand. IS there any of the ready to use MASM code for that?
Quote
if we use push eax and pop edx then we dont need mov edx, r_sin and mov eax, r_cos.
Is this right ? That's all.
Yes you are right.
Quote
mov eax,r_sin ; <= ERROR => change mov r_sin , eax
; push eax ; r_sin
This is right too. Im just know it this morning. I think you have understand. :U
Quote from: Farabi on June 21, 2005, 03:24:05 AM
Quote from: daydreamer on June 20, 2005, 04:56:29 PM
why not use bresenhams circlealgo instead?
Because I dont understand. IS there any of the ready to use MASM code for that?
there is, you can just need to change it from using 16-bit registers, download the Gbook and code examples are included to understand several line algos, and circle algo, clipping algo
http://www.rbthomas.freeserve.co.uk/Downloads.html
So is the the problem solved? Why it crash?
Crash on Win98, annoying error. I cannot close it. Why it run on XP but not on Win98. I dont have Win98 here.