flat assembler
Message board for the users of flat assembler.
Index
> Windows > [Example] Sprite with GDI |
Author |
|
Krecik 22 Jul 2012, 09:45
I'm going to write a simple open-source 2D game in FASM. I know that it is a long way for the beginner but I would like to seek your opinion.
Here is my algorithm for copying a image to buffer: Code: macro Sprite Image*, DestX*, DestY*, SrcWidth*, SrcHeight* { local .height, .width, .transparent xor ecx, ecx xor edx, edx .height: xor eax, eax ;X .width: cmp byte [Image+eax*4+3+ecx], 0 ;If byte is transparent jnz .transparent ;Then go to .transparent mov ebx, [Image+eax*4+ecx] mov [Buffer+DestX*4+DestY*Width*4+eax*4+edx], ebx .transparent: inc eax cmp eax, SrcWidth jb .width add ecx,SrcWidth*4 add edx,Width*4 cmp ecx,SrcWidth*SrcHeight*4 jb .height } How to use: • First we copy as much as we want images to buffer Code: Sprite MyImage1, 400, 200, 150, 100 Sprite MyImage2, 50, 10, 40, 200 ... • Than we call framebuffer. Code: invoke SetDIBitsToDevice,[hDC],0,0,Width,Height,0,0,0,Height,Buffer,bmi,0 Just simple. I attach example with source that display "monster" image. What is the image.bin file in the attachment? It is just image converted specially for my example. Every pixel consist of 4 bytes (the first three are RGB and 4th is transparent setting). My code works only with this images format. What do you think about it? #Edit: I attach fixed files. #Edit 2: I changed a few things. Look here
Last edited by Krecik on 31 Jul 2012, 20:39; edited 3 times in total |
|||||||||||
22 Jul 2012, 09:45 |
|
JohnFound 22 Jul 2012, 09:55
You need to rework your example. It is inexcusable to have 1.8MB .exe file because of data block full of $FF
|
|||
22 Jul 2012, 09:55 |
|
JohnFound 22 Jul 2012, 13:31
You can use static arrays. Only place it at the last place and define it as "?":
Code: section '.data' data readable writeable _class TCHAR 'FASMWIN32',0 _title TCHAR 'Sprite Test',0 _error TCHAR 'Startup failed.',0 wc WNDCLASS 0,WindowProc,0,0,NULL,NULL,NULL,COLOR_BTNFACE+1,NULL,_class MyMonster: file 'image.bin' msg MSG hDC dd ? hwnd dd ? Buffer rd Width*Height bmi BITMAPINFOHEADER And then if you really need white background, put at the beginning: Code: mov edi, Buffer mov ecx, Width*Height mov eax, $ffffff rep stosd |
|||
22 Jul 2012, 13:31 |
|
Picnic 22 Jul 2012, 14:41
Hi,
VirtualAlloc returns a pointer to the address of the allocated memory. You place that pointer in [Buffer] So pass that pointer to function with brackets. Code: invoke SetDIBitsToDevice,[hDC],0,0,Width,Height,0,0,0,Height,[Buffer],bmi,0 A small fix here Code: ;mov [Buffer+DestX*4+DestY*Width*4+eax*4+edx], ebx lea edi, [DestX*4+DestY*Width*4+eax*4+edx] add edi, [Buffer] mov [edi], ebx p.s. I don't know what SetDIBitsToDevice does, but it seems to work now... |
|||
22 Jul 2012, 14:41 |
|
Krecik 22 Jul 2012, 15:42
Thank you both.
I attach new files. Now EXE has 18,5 KB. I hope this size is enough small. JohnFound: Can you explain me how your code works? Code: mov edi, Buffer mov ecx, Width*Height mov eax, $ffffff rep stosd Btw what do you think about my idea "sprite with GDI"? |
|||
22 Jul 2012, 15:42 |
|
bzdashek 23 Jul 2012, 05:47
Good job, Krecik
|
|||
23 Jul 2012, 05:47 |
|
r22 23 Jul 2012, 11:59
@Krecik
Code: mov edi, Buffer ;; address mov ecx, Width*Height ;; size mov eax, $ffffff ;; value rep stosd ;; repeat store dword It's equivalent to the "memset" api. REP is an opcode prefix that will repeat the opcode after it, ECX (value of count register) number of times (in this case until ECX = 0). STOSD will store the dword value of EAX at the address of EDI it will then increment or decrement EDI by 4 bytes (depending on the DF-directional flag). You can lookup up these instructions in the manual. |
|||
23 Jul 2012, 11:59 |
|
AsmGuru62 23 Jul 2012, 14:41
@Krecik:
You call VirtualAlloc in your main message loop and never call VirtualFree. Is that right? So, how long the game plays? |
|||
23 Jul 2012, 14:41 |
|
Enko 23 Jul 2012, 15:12
Quote:
I did once a simple sprite 2d engine with gdi. The problem is alpha and transparent sprites. its not a bad idea implement some linked list for the sprites. An example: Sprite.Move ;moves function to move the sprite, Code: mySprite SPRITE mov [mySprite.Move], mySpriteProc proc mySpriteProc ret endp Sprite.doCollison The proc you call if the sprite collied with another sprite. Sprite.Draw ;same thing Engine.AddSprite Code:
Engine.AddSprite, mySprite
Engine.Move Code: ;pseudocode for i = 0, i<= Engine.SpriteCount { Engine.Sprite[i].Move(); } ;you call al the Move procs of the sprites added to the engine Engine.Draw ;same thing. Engine.RemoveSprite Engine.TestCollision Code: ;test the collition bettween all the sprites of the engine somthing like for i=0, i<=Engine.Sprite.Count for j=i, j<=Engine.SpriteCount if Collision(Engine.Sprite[i], Engine.Sprite[j]) Engine.Sprite[i].doCollision() Engine.Sprite[j].doCollision() |
|||
23 Jul 2012, 15:12 |
|
Krecik 24 Jul 2012, 13:49
r22:
Thank you for explain. Now I understand it. AsmGuru62: I think you are right but I don't use Virtal~ functions yet. Enko: You can use my transparent method in your engine. |
|||
24 Jul 2012, 13:49 |
|
AsmGuru62 24 Jul 2012, 14:01
I am thinking of writing a small demo with sprites.
But I do not want to draw them (sprites) -- where I can download some ready images? |
|||
24 Jul 2012, 14:01 |
|
Enko 24 Jul 2012, 14:37
|
|||
24 Jul 2012, 14:37 |
|
Krecik 31 Jul 2012, 20:36
I recently worked on the my project and I added few changes.
Here is a new algorithm for copying sprites to buffer: Code: fSprite: imul ecx, [ScreenWidth] add ecx, ebx imul ecx, 4 mov ebx, [ScreenWidth] imul ebx, 4 mov esi, [eax] imul esi, [eax+4] xor edx, edx xor edi, edi .height: .width: cmp byte [eax+8+edx*4+3], 0 jnz .transparent mov ebp, [eax+8+edx*4] mov [Buffer+edi*4+ecx], ebp .transparent: inc edx inc edi cmp edi, [eax] jb .width xor edi, edi add ecx, ebx cmp edx, esi jb .height ret Now it is a normal function which you can call using macro Sprite. Code: macro Sprite Image*, DestX*, DestY* { mov ecx, DestY mov ebx, DestX lea eax, [Image] call fSprite } Example parameters for this macro: Code: Sprite Image123, 300, 50 If you take look for a image.bin you can see that it has been changed too. Now the first two bytes are width and height of the image. The rest of my file type is the same. I added also a speed test. It shows how many sprites are copying to buffer per second. Just look for a new attachment! My computer: Quote: Windows XP Displays 60,000 - 70, 000 spr/sec. I have a question: how can I simply switch between 32-bit and 64-bit OS without code editing (include win32ax/64ax doesn't work) O maybe is some method to do program working on both? |
|||
31 Jul 2012, 20:36 |
|
Madis731 01 Aug 2012, 12:12
You can make an assembly time variable that you change and make the necessary edits in your code, but there is no such thing as a universal code. There must be 2 paths in your code: one for 32 and the other for 64 bits. Btw, does anyone know the statistics about 64-bit OS-s being used around the world?
You can change imul ecx, 4 imul ebx, 4 to shl ecx,2 shl ecx,2 to make the setup a bit faster for smaller sprites. You could also get rid of the transparency check by reading both SRC and DST pixels and then conditionally (CMOVxx) overwriting the DST. |
|||
01 Aug 2012, 12:12 |
|
AsmGuru62 01 Aug 2012, 13:26
I think PE formats also different between 32-bit and 64-bit.
So, to run it natively -- it needs to have been compiled into two PE files. |
|||
01 Aug 2012, 13:26 |
|
revolution 01 Aug 2012, 14:01
The main difference with 64-bit is the addressing, so in most circumstances it isn't actually necessary to write 64-bit code unless you need to address large (> ~2GB-3GB) portions of memory. In many cases using the 32-bit binary is perfectly usable.
Of course you can't use the 64-bit native integer arithmetic unless you use 64-bit code but often this is not a deal-breaker as many compute intensive applications use the FPU/SSE units. |
|||
01 Aug 2012, 14:01 |
|
Xorpd! 01 Aug 2012, 17:42
GoAsm has some tools to enable 32/64 bit code on the source code level to some extent. I have never used them, though. You can write a 32/64 bit binary but I think you would also need to write 32-bit and 64-bit stub programs that load the 32/64 bit binary into memory and jump into it because I don't think Windows lets you specify such an executable or dll. Normally the 32/64 bit code would start with a test for bitness then jump to the correct code. Code that just contained an instruction stream interpretable as something useful in both 32-bit and 64-bit modes would be extremely beautiful but also challenging to compose.
|
|||
01 Aug 2012, 17:42 |
|
Madis731 02 Aug 2012, 06:44
To an assembly programmer 64-bit is highly valuable because of the 8 additional GPRs and SSE registers.
Where I'm getting at is the world might be switching over to 64-bit completely just because people are starting to have 4GB+ RAM on board and they need to address 2GB of video memory and what-not. For example if we take this 32-bit fSprite call then you can see that we're running out of registers. Rewriting this function to 64-bit can achieve better performance and less LOC. Btw, I love this idea, but I agree that its nearly impossible: Xorpd! wrote: Code that just contained an instruction stream interpretable as something useful in both 32-bit and 64-bit modes would be extremely beautiful but also challenging to compose. |
|||
02 Aug 2012, 06:44 |
|
< Last Thread | Next Thread > |
Forum Rules:
|
Copyright © 1999-2024, Tomasz Grysztar. Also on GitHub, YouTube.
Website powered by rwasa.