Ultima Online and 16-bit lighting effects
First i would like to say long time listener first time poster..hehe.
Ok, ok..here i go:
I went to ultima online site today www.uo.com to take a look at the graphics they use in game..i liked the style and is exactly like what i want to use for my design i am planning.
So:
1) If you have seen the graphics or played game i would like to know if they use "iso" or "tile-based looking like iso" tilesets. They are exactly the idea of style i would like to have..no need to comment on how hard it would be or the need of a team of graphic artists..its only the style i look for cuz i know im no great artist 8)
2) They use 16-bit graphics with lighting effects such as day/night, torches/lights, etc. So, my question is how do they create the change in day..if thats what they really do. I know in a 8-bit palette you can manipulate palettes to create darker colors, animation, etc...but how do you do that with a 16-bit engine?? Do you have to creat a whole new set of tiles with a different shade(say darker for night-time) or do they do something else. I especially like the torch in caves, day/night realism but havent seen any subjects on how to do it for a 2D tile-based game.
sheww. well i broke the ice and will eagerly be watching for some insightful comments from all you crazy iso-landers. 8) cyas...
Ultima Online uses a diamond shape tile 44x44 pixels exactly. Their file formats are fairly complicated but you can find out all about them
here
As for their day night sequences, I think they do this in asm, as I''ve played UO before on a P133 with an old 2mb video card and it still ran a slow but decent framerate.
There''s lots of source out there (MMX enhanced as well) to do fades on your screen. Basically you render your scene, then run the fade code on your backbuffer. Then flip
As for their localized lighting, I think they define an area around a light source, and during the fade (if it''s not daylight level) skip the areas that have light sources. I''m not exactly sure about this though.
Their lighting method is not that advanced and I''ve noticed light goes through walls.
here
As for their day night sequences, I think they do this in asm, as I''ve played UO before on a P133 with an old 2mb video card and it still ran a slow but decent framerate.
There''s lots of source out there (MMX enhanced as well) to do fades on your screen. Basically you render your scene, then run the fade code on your backbuffer. Then flip
As for their localized lighting, I think they define an area around a light source, and during the fade (if it''s not daylight level) skip the areas that have light sources. I''m not exactly sure about this though.
Their lighting method is not that advanced and I''ve noticed light goes through walls.
Thanks for the comments i will have to digest this info about the tiles and your ideas on lighting.
I would like to ask to here more comments about the lighting as i have not seen any other explanations for it (examples, code, etc). Im not saying i dont find your ideas wrong, in fact the fading ideas are good. I just want to here a variety of possible ideas of what some of you out there have actually attempted in this area.
GQ.
I would like to ask to here more comments about the lighting as i have not seen any other explanations for it (examples, code, etc). Im not saying i dont find your ideas wrong, in fact the fading ideas are good. I just want to here a variety of possible ideas of what some of you out there have actually attempted in this area.
GQ.
Had some time to think about the "fading" you elude me too, yet i still have not figured out how to do this. So, first ill give my idea of fading which is either randomly setting pixels to a dark or black color, OR as some kind of routine that goes through every the pixels in memory and shifts the rgb to a darker shade.
(Let me state that i am using directX and all that directdraw stuff so you can let me reference stuff in sdk if you know it.)
I assume that somehow the second is prefered(or another way) as the first will only destroy the image and not make it darker. So how in directX would i perform these lighting tricks and shading of colors if 16-bit colors are used.
*sniff, sniff..i hate when i dont grasp something*
GQ
(Let me state that i am using directX and all that directdraw stuff so you can let me reference stuff in sdk if you know it.)
I assume that somehow the second is prefered(or another way) as the first will only destroy the image and not make it darker. So how in directX would i perform these lighting tricks and shading of colors if 16-bit colors are used.
*sniff, sniff..i hate when i dont grasp something*
GQ
Let me see if I can explain it. First of all, it''s require that you write your own little blt function just for this aspect
Let''s first say that you have a pointer to your 16bit DirectX surface. This variable is declared as:
short *ptrSurface = NULL;
You also need an illumination map that is the exact same size (in bytes) as the surface. This is the dwHeight * lPitch in the DDSURFACEDESC struct. This variable is declared as:
short *ptrIllum = NULL;
With each object that radiates light, have a pre-initialized array of shorts that contains the brightness level of the pixels around the object. The higher the short value, the brighter the pixel is. The center of the array (if viewed as a 2D array) should be the brightest. Let''s say this array has the 2D dimensions mTorchLW, mTorchLH (width, height respectively).
Before you draw the map, first set the default illumination level... the ambience if you will. This is the brightness of everything that''s not in the range of an object that radiates light.
You should first loop through the objects that would be on the screen and check to see if it radiates light. For all the objects that illuminate light, you will have to modify the short values in the illumination map accordingly. This is hard to explain, but easy to implement.
Basically what you do is first figure out where the object would be on the screen. With that coordinate, you would find the equivilant ''pixel'' on the illumination map.
Now that you have the pixel spot where you draw your torch, calculate where it''s base is. That is usually just the height of the torch. Now that you have that value (BaseX, BaseY), you can calculate where to start setting your illumination. That is:
IllumStartX = BaseX - (mTorchLW >> 1);
IllumStartY = BaseY - (mTorchLH >> 1);
Scan across the illum. map and torch illum. map. Check the illum. map''s light value. If it''s less than the torch''s illum. map value, then set illum. map''s light value to whatever is in the torch''s illum map. Pretty confusing, huh. Don''t worry... it''s not hard to implement.
Now that the comparison is all done and the illumination map is set, draw your map like normal. Once that is done, run the surface through your blt function that will apply the illumination level. Start with the pointer at the beginning of the surface and the illum. map. Scan through each and every pixel on the surface and set the illum level.
I haven''t check to see if this compiles, but you should get the general idea. SurfSize is the number of pixels to be processes, not the number of bytes.
I hope that helps... and if it doesn''t I hope that it doesn''t make things worse.
Dino M. Gambone
Good judgement is gained through experience. Experience, however, is gained through bad judgement.
Let''s first say that you have a pointer to your 16bit DirectX surface. This variable is declared as:
short *ptrSurface = NULL;
You also need an illumination map that is the exact same size (in bytes) as the surface. This is the dwHeight * lPitch in the DDSURFACEDESC struct. This variable is declared as:
short *ptrIllum = NULL;
With each object that radiates light, have a pre-initialized array of shorts that contains the brightness level of the pixels around the object. The higher the short value, the brighter the pixel is. The center of the array (if viewed as a 2D array) should be the brightest. Let''s say this array has the 2D dimensions mTorchLW, mTorchLH (width, height respectively).
Before you draw the map, first set the default illumination level... the ambience if you will. This is the brightness of everything that''s not in the range of an object that radiates light.
You should first loop through the objects that would be on the screen and check to see if it radiates light. For all the objects that illuminate light, you will have to modify the short values in the illumination map accordingly. This is hard to explain, but easy to implement.
Basically what you do is first figure out where the object would be on the screen. With that coordinate, you would find the equivilant ''pixel'' on the illumination map.
Now that you have the pixel spot where you draw your torch, calculate where it''s base is. That is usually just the height of the torch. Now that you have that value (BaseX, BaseY), you can calculate where to start setting your illumination. That is:
IllumStartX = BaseX - (mTorchLW >> 1);
IllumStartY = BaseY - (mTorchLH >> 1);
Scan across the illum. map and torch illum. map. Check the illum. map''s light value. If it''s less than the torch''s illum. map value, then set illum. map''s light value to whatever is in the torch''s illum map. Pretty confusing, huh. Don''t worry... it''s not hard to implement.
Now that the comparison is all done and the illumination map is set, draw your map like normal. Once that is done, run the surface through your blt function that will apply the illumination level. Start with the pointer at the beginning of the surface and the illum. map. Scan through each and every pixel on the surface and set the illum level.
void SetIllumLvl(short *SurfPixels, short *IllumMap, unsigned long SurfSize){
short *cur_pixel, *cur_illum
cur_pixel = SurfPixels;
cur_illum = IllumMap
while (SurfSize){
//This next line takes the pixel value and times it
// by the light level.
*cur_pixel = ((*cur_pixel * cur_illum) / 0x0000FFFF);
//Move to the next pixel
++cur_pixel; ++cur_illum;
--SurfSize;
}
}
I haven''t check to see if this compiles, but you should get the general idea. SurfSize is the number of pixels to be processes, not the number of bytes.
I hope that helps... and if it doesn''t I hope that it doesn''t make things worse.
Dino M. Gambone
Good judgement is gained through experience. Experience, however, is gained through bad judgement.
Now i gettt itttt. Sweat!
Your explaination is very good Dino, its almost exactly what i needed to hear.(PS thanks also Darrell.)
Im sure many others will be glad to read it too since ive looked through all the posts(365 days worth) and not one explained it, at least not to my knowledge....good job!
I will take a few days to really think about it ...in the mean time can you explain 1 little thing: your need to divide the new pixel illumination value by hex number 0x0000ffff? what does this do and its purpose?
Anyways, just wanna say how stoked i am to have found a wealth of knowledgable folks willing to share!! 8)
Your explaination is very good Dino, its almost exactly what i needed to hear.(PS thanks also Darrell.)
Im sure many others will be glad to read it too since ive looked through all the posts(365 days worth) and not one explained it, at least not to my knowledge....good job!
I will take a few days to really think about it ...in the mean time can you explain 1 little thing: your need to divide the new pixel illumination value by hex number 0x0000ffff? what does this do and its purpose?
Anyways, just wanna say how stoked i am to have found a wealth of knowledgable folks willing to share!! 8)
When drawing the map normally, you go under the assumption that the light level is at 100%. That means that the value of the pixel is 0 to 65536 (or 0x0000FFFF). This is the actual color of the pixel.
The basic idea behind the illumination map is that it represents the degree of brightness. The actual formula is suppose to be:
new color = original color * (light level / max light level).
In a 16 bit illumination map, max light level is 65536. The previous post had the () in the wrong spots that made it confusing.
Now that I know you understand that concept... here''s some optimization you can do:
1) You technically don''t have to use 16 bit values for the illumination map. You could go 8 bit. It works the same way except that you divide by 0x000000FF and not 0x0000FFFF.
2) You can take out the division and replace with a bit shift. If you do this, then here''s the formula and you MUST () the * portions (due to operator precedence):
new_clr = ((orig_clr * light_lvl) >> 16) & 0x0000FFFF;
-or for 8 bit-
new_clr = ((orig_clr * light_lvl) >> 8) & 0x0000FFFF;
They both do the same as dividing by 65536 and 256, respectively. The 0x0000FFFF is to make sure you get a valid 16 bit valu.
Note: this is a very basic method of doing illumination. This is what I gathered by looking at the UO screenshots and as you may have noticed, the light rays weren''t being clipped. Clipping the light is alot harder to do, but there are ways.
If each type of object that illuminates light has it''s own ''light array'' like the example I gave with the torch, then you can to cool tricks like changing the array so that the lit areas ''flicker'' a bit.
Good Luck and I hope this helps you out.
Dino M. Gambone
Good judgement is gained through experience. Experience, however, is gained through bad judgement.
The basic idea behind the illumination map is that it represents the degree of brightness. The actual formula is suppose to be:
new color = original color * (light level / max light level).
In a 16 bit illumination map, max light level is 65536. The previous post had the () in the wrong spots that made it confusing.
Now that I know you understand that concept... here''s some optimization you can do:
1) You technically don''t have to use 16 bit values for the illumination map. You could go 8 bit. It works the same way except that you divide by 0x000000FF and not 0x0000FFFF.
2) You can take out the division and replace with a bit shift. If you do this, then here''s the formula and you MUST () the * portions (due to operator precedence):
new_clr = ((orig_clr * light_lvl) >> 16) & 0x0000FFFF;
-or for 8 bit-
new_clr = ((orig_clr * light_lvl) >> 8) & 0x0000FFFF;
They both do the same as dividing by 65536 and 256, respectively. The 0x0000FFFF is to make sure you get a valid 16 bit valu.
Note: this is a very basic method of doing illumination. This is what I gathered by looking at the UO screenshots and as you may have noticed, the light rays weren''t being clipped. Clipping the light is alot harder to do, but there are ways.
If each type of object that illuminates light has it''s own ''light array'' like the example I gave with the torch, then you can to cool tricks like changing the array so that the lit areas ''flicker'' a bit.
Good Luck and I hope this helps you out.
Dino M. Gambone
Good judgement is gained through experience. Experience, however, is gained through bad judgement.
Dino,
One question:
By implementing this technique would you have to create a new blitting function that draws the bitmaps that accomodates this?
I guess not 'cause the function would adjust the bitmaps on a pixel level, right?
also for this:
what would *SurfPixels be?
Would *IllumMap be the array that holds the illum map?
would SurfSize be the size of the whole screen...like 640x480?
Sorry your explanation is good, but I'm still a little fuzzy when it gets into this sort of thing
""" "'Nazrix is cool' -- Nazrix" --Darkmage --Godfree"-Nazrix" -- runemaster --and now dwarfsoft" -- dwarfsoft
Need help? Well, go FAQ yourself.
Edited by - Nazrix on October 9, 2000 8:52:05 PM
One question:
By implementing this technique would you have to create a new blitting function that draws the bitmaps that accomodates this?
I guess not 'cause the function would adjust the bitmaps on a pixel level, right?
also for this:
void SetIllumLvl(short *SurfPixels, short *IllumMap, unsigned long SurfSize)
what would *SurfPixels be?
Would *IllumMap be the array that holds the illum map?
would SurfSize be the size of the whole screen...like 640x480?
Sorry your explanation is good, but I'm still a little fuzzy when it gets into this sort of thing
""" "'Nazrix is cool' -- Nazrix" --Darkmage --Godfree"-Nazrix" -- runemaster --and now dwarfsoft" -- dwarfsoft
Need help? Well, go FAQ yourself.
Edited by - Nazrix on October 9, 2000 8:52:05 PM
short *SurfPixels is the pointer to the DirectX surface.
short *IllumMap is the pointer to your illumination array (the big one).
unsigned long SurfSize is the number of pixels in the surface. If your surface is 640 x 480 then the SurfSize would be (640 * 480, which is 307200).
The only blitting function that you would have to implement is one that overlays the entire illumination map object to already drawn screen. The order would be:
Does that clear things up?
Dino M. Gambone
Good judgement is gained through experience. Experience, however, is gained through bad judgement.
short *IllumMap is the pointer to your illumination array (the big one).
unsigned long SurfSize is the number of pixels in the surface. If your surface is 640 x 480 then the SurfSize would be (640 * 480, which is 307200).
The only blitting function that you would have to implement is one that overlays the entire illumination map object to already drawn screen. The order would be:
1. Reset the illumination map to the ambience light level2. Loop through all the objects, drawing them to your surface and modifying the illumination map at the same time.3. Get the pointer to the DirectX surface you have been drawing to.4. Pass that pointer, the pointer to the illumination map, and the size of the surface (# of pixels) to the SetIllumLvl() function.5. Flip() or do whatever you normally do to get the back buffer to the screen.
Does that clear things up?
Dino M. Gambone
Good judgement is gained through experience. Experience, however, is gained through bad judgement.
oh...so would the "big" illumination map be the same amount of elements as the number of pixels you're using for the whole screen?...
like illumination_array[640][480] if you are using 640x480 for the resolution?
also is it sort of like you're drawing the whole screen to the back buffer then altering the pixels that need to be changed with the SetIllumLvl() function before the Flip()?
So, the SetIllumLvl() function is actually altering the color values? I think I'm starting to get it now At least I hope.
"""" "'Nazrix is cool' -- Nazrix" --Darkmage --Godfree"-Nazrix" -- runemaster --and now dwarfsoft" -- dwarfsoft --pouya" -- Nazrix
Need help? Well, go FAQ yourself.
Edited by - Nazrix on October 9, 2000 9:09:09 PM
like illumination_array[640][480] if you are using 640x480 for the resolution?
also is it sort of like you're drawing the whole screen to the back buffer then altering the pixels that need to be changed with the SetIllumLvl() function before the Flip()?
So, the SetIllumLvl() function is actually altering the color values? I think I'm starting to get it now At least I hope.
"""" "'Nazrix is cool' -- Nazrix" --Darkmage --Godfree"-Nazrix" -- runemaster --and now dwarfsoft" -- dwarfsoft --pouya" -- Nazrix
Need help? Well, go FAQ yourself.
Edited by - Nazrix on October 9, 2000 9:09:09 PM
This topic is closed to new replies.
Advertisement
Popular Topics
Advertisement