Valhalla Legends Forums Archive | Advanced Programming | StarCraft + DirectDraw + SoftIce

AuthorMessageTime
mouki
SC uses DDraw, though it loads DDraw.dll dynamically(LoadLibrary).When i add a breakpoint to DDraw's function "DirectDrawCreate" (afte i've loaded DDraw.dll with symbol loader) SoftIce does not pop up.If i wanna draw something on StarCraft's screen i have to right straight to the backbuffer? or some GDI calls should do the work ?
June 9, 2003, 12:28 PM
EvilCheese
Backbuffer Creation:

[code]
.text:004D7AE2 mov eax, dword_6B6E8C
.text:004D7AE7 lea edx, [esp+4F0h+var_4E4]
.text:004D7AEB mov [esp+4F0h+var_4E4], esi
.text:004D7AEF mov [esp+4F0h+var_4E0], 7
.text:004D7AF7 mov [esp+4F0h+var_47C], 840h
.text:004D7AFF mov [esp+4F0h+var_4D8], 280h
.text:004D7B07 mov [esp+4F0h+var_4DC], 1E0h
.text:004D7B0F mov ecx, [eax]
.text:004D7B11 push offset dword_6B6E94
.text:004D7B16 push edx
.text:004D7B17 push eax
.text:004D7B18 call dword ptr [ecx+18h]
.text:004D7B1B test eax, eax
.text:004D7B1D jz short loc_4D7B4F

[/code]

[code]
HRESULT CreateSurface(
LPDDSURFACEDESC lpDDSurfaceDesc,
LPDIRECTDRAWSURFACE FAR *lplpDDSurface,
IUnknown FAR *pUnkOuter
);
[/code]

dword_6B6E8C = LPDIRECTDRAW (Pointer to the app's directdraw object)

[esp+4F0h+var_4E4] = LPDDSURFACEDESC (Pointer to desired surface description)

dword_6B6E94 = LPDIRECTDRAWSURFACE (Address to receive the pointer of the created DD Surface object)

Using this information, it should be fairly straightforward to commandeer the backbuffer surface from your own code.

I would recommend hooking into the main game drawing loop and carrying out your drawing functions from there, as this has the advantage of leaving the game to acquire DCs and lock the surface prior to drawing.. as well as freeing everything afterwards.

Since this code is already present, it would make little sense to duplicate it.

This would also have the advantage of removing any flicker from your overlayed display, since you would be syncing with the game's frame-refresh.

The easier alternative is to acquire the DC of the primary surface via the window handle for SC, and then draw straight to that using standard GDI functions, the disadvantages in this case being speed and a lack of synchronisation. This means your display will have a (maybe insignificant, but still present) impact on the performance of the game, as well as flickering in a very annoying fashion.

The only other thing to remember is that SC uses an 8-bit palletized display, so you will be unable to get accurate RGBA color reproduction.. you'll have to experiment and find colors that work within the palette.

Hope that helps somewhat :)

Edit: Rewrote the whole reply to make it more informative and easier to follow + corrected mistakes :P
June 9, 2003, 2:31 PM
indulgence
There is a copy of a .pal (palette) that has the SC Palette entries...

Plus, it might be better to commandeer starcraft right before it swaps the backbuffer to the main surface, otherwise StarCraft might go and do something naughty - like draw over your graphics
June 10, 2003, 2:36 AM
EvilCheese
It would also be possible to interrogate the logical palette of the surface using the IDirectDrawSurface::GetPalette member function.

Once you retrieve a pointer to the palette structure, you can then use the IDirectDrawPalette::GetEntries member to obtain a list of the palette entries into a buffer of your choosing.

Walk these entries to find the closest color description to your desired RGB value.

For the sake of speed, it is best not to do this on a per-frame basis, rather keep a simple array of the colors used by your code and assign them palette index values only on startup, or when the logical palette changes.

The best place to intercept the code would depend largely on what effect you were trying to acheive, and how much of the SC display you wanted under or over your own drawing.

For a complete overlay I would recommend searching for a call to the IDirectDrawSurface::Unlock or IDirectDrawSurface::ReleaseDC members, and placing your hook right before that call, as these usually signify the end of the current drawing cycle. (::ReleaseDC calls the internal version of ::Unlock anyway).
June 10, 2003, 2:13 PM
indulgence
[quote author=EvilCheese link=board=23;threadid=1590;start=0#msg11990 date=1055254401]
It would also be possible to interrogate the logical palette of the surface using the IDirectDrawSurface::GetPalette member function.

Once you retrieve a pointer to the palette structure, you can then use the IDirectDrawPalette::GetEntries member to obtain a list of the palette entries into a buffer of your choosing.

Walk these entries to find the closest color description to your desired RGB value.

For the sake of speed, it is best not to do this on a per-frame basis, rather keep a simple array of the colors used by your code and assign them palette index values only on startup, or when the logical palette changes.

The best place to intercept the code would depend largely on what effect you were trying to acheive, and how much of the SC display you wanted under or over your own drawing.

For a complete overlay I would recommend searching for a call to the IDirectDrawSurface::Unlock or IDirectDrawSurface::ReleaseDC members, and placing your hook right before that call, as these usually signify the end of the current drawing cycle. (::ReleaseDC calls the internal version of ::Unlock anyway).

[/quote]

Why use DirectDraw at all? You could create just grab the palette entries from memory... Even though this is rather pointless. An enum of palette entries would be fine. Incorporating directdraw into the app would be like packing your whole wardrobe for a 2 day trip.
June 11, 2003, 8:34 PM
Adron
You will probably want to code your colors from the palette anyway. Starcraft animates the palette so if you try to match an RGB color at runtime you might happen to pick a match that is animating...

You could I suppose also take the animation into account and not match against those entries, but I still think it's better to use the right palette. Design your graphics for the palette in use.
June 12, 2003, 7:43 PM
EvilCheese
[quote]
Why use DirectDraw at all?
[/quote]

Use Directdraw because the game uses DirectDraw and has everything all nicely set up for you to take advantage of.

Add to this that standard GDI is slower by a factor too large to state accurately, and you'll see why.

[quote]
Incorporating directdraw into the app would be like packing your whole wardrobe for a 2 day trip.
[/quote]

More like using a lawnmower to mow your lawn instead of hair scissors. :P

[quote]
Starcraft animates the palette so if you try to match an RGB color at runtime you might happen to pick a match that is animating...
[/quote]

Something worth taking into account, although if you update your color tables on palette change this should be rendered a nonissue.

Overall it would be easier to use a predefined palette, for Starcraft specifically, but in general terms it is better to make sure your program has an up-to-date reference of color entries for drawing. Helps to ensure forward-compatibility also (who knows whether the palette might be totally rearranged in a future patch, or in a situation you hadn't considered?)
June 12, 2003, 9:00 PM
indulgence
[quote author=EvilCheese link=board=23;threadid=1590;start=0#msg12193 date=1055451631]
[quote]
Why use DirectDraw at all?
[/quote]

Use Directdraw because the game uses DirectDraw and has everything all nicely set up for you to take advantage of.

Add to this that standard GDI is slower by a factor too large to state accurately, and you'll see why.

[quote]
Incorporating directdraw into the app would be like packing your whole wardrobe for a 2 day trip.
[/quote]

More like using a lawnmower to mow your lawn instead of hair scissors. :P

[quote]
Starcraft animates the palette so if you try to match an RGB color at runtime you might happen to pick a match that is animating...
[/quote]

Something worth taking into account, although if you update your color tables on palette change this should be rendered a nonissue.

Overall it would be easier to use a predefined palette, for Starcraft specifically, but in general terms it is better to make sure your program has an up-to-date reference of color entries for drawing. Helps to ensure forward-compatibility also (who knows whether the palette might be totally rearranged in a future patch, or in a situation you hadn't considered?)

[/quote]

Who said use standard GDI... You could write a blitting routine in ASM which would pwn directdraw's FastBlt...

The lawnmower/scissors comment is a bit odd... i dont see it that way, my blitting routines are fast enough and i have a couple (draw and fill a square and an alphablending copy from resource. What more would I need?
June 13, 2003, 5:23 AM
EvilCheese
To acheive blitter speeds faster than directdraw using ASM, you will need to interface directly with the frame memory of the graphics hardware.

If you're blitting directly to the SC display memory, then you're using DirectDraw, whether it be directly or indirectly.

AFAIAA There are three ways to blit a bitmap into a display window in the way you're describing.

The first involves creating a bitmap, and then loading it into your window using GDI SelectObject, then blitting to that bitmap whether using your own functions or the functions provided by GDI.... either way this limits you to the drawing speed constraints imposed by Windows, as the final rendering is still done by GDI.

The second method involves blitting into the DC using GDI functions directly.... but again this uses GDI.

The third method is to write to the memory of the display buffer directly.

Unfortunately, Windows provides no way to directly access the video memory of a surface save through DirectX or the creation of your own custom display driver interface.

Your blitting function will still have to use the IDirectDrawSurface::Lock() member to obtain a pointer to the memory of the surface, or obtain a pointer to the memory already locked in this fashion.

However it is wise to remember that this pointer remains valid only for as long as the current surface lock is in place. Once unlocked, writing or reading this buffer will cause undefined results.

Whether you use your own custom blit routine or take advantage of DirectDraw's blit routines makes little difference, you will generally be unable to obtain a direct pointer to the display memory within windows without the use of DirectDraw in some fashion, whether it be by interfacing with it in your code, or inheriting a pointer already obtained by SC via DirectDraw functions.

This is, incidentally, the whole reason that DirectDraw exists. :)

Edit: Neglected to mention: The majority of graphical hardware produced in the last 10 years features a custom blitter processor of some kind, designed to streamline the process of copying and performing fast raster operations on large areas of memory through asynchronous operation.

Natively, the DirectDraw API will utillise this hardware where possible, meaning the chances of you writing an asm blit routine which operates faster than IDirectDrawSurface::BltFast - even with access to the display memory - are extremely slim.

If you'd like to post your code however, I'd be very interested to see it. :)
June 13, 2003, 2:45 PM

Search