Allegro.cc Forums » Programming Questions » Math help, please

 This thread is locked; no one can reply to it. 1   2   3
 Math help, please
23yrold3yrold
Member #1,134
March 2001

I'll start a new thread for this, since it's buried in other threads where no one will see it

I'm trying to save time by skipping offscreen pixels en masse in my little column blitter, but it's messing the texture up a bit. I'm attaching a screenie (the jagginess only appears in walls taller than the screen) and posting the code; does anyone see the problem?

 1 void DrawSlice(BITMAP* buffer, BITMAP* texture, int xoff, int x, int y, int tall) 2 { 3 int srcy = 0, num = 0; 4 5 // skip down until we hit the top of the screen (for very close walls) 6 // this bit is currently a little buggy ... 7 if(tall > SCREENHEIGHT) 8 { 9 num = 64 * ((tall - SCREENHEIGHT) / 2); 10 11 if(num >= tall) 12 { 13 srcy = num / tall; 14 num = num % 64; 15 } 16 17 y = 0; 18 } 19 20 // draw that slice! 21 for(int i = y ; i < y + tall ; ++i) 22 { 23 num += 64; 24 25 while(num >= tall) 26 { 27 num -= tall; 28 ++srcy; 29 } 30 31 if(srcy >= 64 || i >= buffer->h) return; 32 33 // this assumes the texture is rotated (otherwise it's slower due to cache missing) 34 ((short *)buffer->line)[x] = ((short*)texture->line[xoff])[srcy]; 35 } 36 }

Thanks

--
Software Development == Church Development
Step 1. Build it.
Step 2. Pray.

aybabtu
Member #2,891
November 2002

Hmm...would this work?

 1 DrawSlice(blah,blah,blah) 2 { 3 //Take out the current code to figure out if it's on screen... 4 // draw that slice! 5 for(int i = y ; i < y + tall ; ++i) 6 { 7 num += 64; 8 9 while(num >= tall) 10 { 11 num -= tall; 12 ++srcy; 13 } 14 15 if(srcy >= 64 || i >= buffer->h) return; 16 17 // this assumes the texture is rotated (otherwise it's slower due to cache missing) 18 19 //Just check for the output Y here? 20 if(i>=0&&iline)[x] = ((short*)texture->line[xoff])[srcy]; 23 } 24 25 } 26 }

Maybe that doesn't help with the speed, though...

 Bob Free Market Evangelist September 2000 if(tall > SCREENHEIGHT)Shouldn't that be: ```if(y + tall > SCREENHEIGHT) ``` ? --- Bob [ -- All my signature links are 404 -- ]
23yrold3yrold
Member #1,134
March 2001

Bob: same diff.

```   y == (tall - SCREENHEIGHT) / 2
```

I'd forgotten about y and tried using that, and got the exact same results ...

 1 void DrawSlice(BITMAP* buffer, BITMAP* texture, int xoff, int x, int y, int tall) 2 { 3 int srcy = 0, num = 0; 4 5 // skip down until we hit the top of the screen (for very close walls) 6 // this bit is currently a little buggy ... 7 if(y < 0) 8 { 9 num = 64 * -y; 10 11 if(num >= tall) 12 { 13 srcy = num / tall; 14 num = num % 64; 15 } 16 17 y = 0; 18 } 19 20 // draw that slice! 21 for(int i = y ; i < y + tall ; ++i) 22 { 23 num += 64; 24 25 while(num >= tall) 26 { 27 num -= tall; 28 ++srcy; 29 } 30 31 if(i < 0) continue; 32 if(srcy >= 64 || i >= buffer->h) return; 33 34 // this assumes the texture is rotated (otherwise it's slower due to cache missing) 35 // ((short *)buffer->line)[x] = (((short*)texture->line[xoff])[srcy] >> 1 & 0x7BEF); 36 ((short *)buffer->line)[x] = ((short*)texture->line[xoff])[srcy]; 37 } 38 }

Probably faster though ... there I go; optimizing my errors again

--
Software Development == Church Development
Step 1. Build it.
Step 2. Pray.

 Richard Phipps Member #1,632 November 2001 What happens if you make srcy a float? It looks to me that it's slightly off in the starting values for some lines in a pattern which suggests a rounding error in the start y to me..worth a try I guess.
 23yrold3yrold Member #1,134 March 2001 srcy is used to reference a pixel, which means it has use only as an int. I would round it later anyway. --Software Development == Church DevelopmentStep 1. Build it.Step 2. Pray.
 Richard Phipps Member #1,632 November 2001 I'm looking at your picture again where the outlines of the bricks go jaggy. The gaps between the jaggies get bigger as the texture is scaled bigger. There seems to be a general downwards shifting until the texture is drawn jumped up and then it falls down again.It still looks like rounding errors to me.srcy = num / tall;If this line is off by only one on some lines it will produce a jagged effect.(I could be TOTALLY wrong, but could you try it and see?)
 23yrold3yrold Member #1,134 March 2001 No difference at all; sorry --Software Development == Church DevelopmentStep 1. Build it.Step 2. Pray.
 Richard Phipps Member #1,632 November 2001
 Peter Hull Member #1,136 March 2001 Probably it makes a very slight difference but you can take the 'if' out of the loop I think:i>buffer->h can be done by changing the limit of the loop srcy>=64 can at least go in the while loop? (needs thought, that one..)Pete
Fladimir da Gorf
Member #1,565
October 2001

It look like you're not taking in account that the top of the current stretched pixel is above the screen. I have the strangest feeling that the problem lies in:

```num += 64;
```

which doesn't take in account that you're not starting the pixel rendering from the zero offset.
Don't ask me how to fix it, I just can't think right now, but at least the following code might be slightly faster:

 1 void DrawSlice(BITMAP* buffer, BITMAP* texture, int xoff, int x, int y, int tall) 2 { 3 int srcy = 0, num = 0; 4 5 // skip down until we hit the top of the screen (for very close walls) 6 // this bit is currently a little buggy ... 7 if(y < 0) 8 { 9 num = 64 * -y; 10 11 if(num >= tall) 12 { 13 srcy = num / tall; 14 num = num % 64; 15 } 16 17 y = 0; 18 } 19 20 // draw that slice! 21 22 // Added a pointer to the current texture pixel // 23 short *texturePointer = (short*)texture->line[xoff] + srcy; 24 for(int i = y ; i < y + tall ; ++i) 25 { 26 num += 64; 27 28 while(num >= tall) 29 { 30 num -= tall; 31 ++srcy; 32 ++texturePointer; 33 } 34 35 if(i < 0) continue; 36 if(srcy >= 64 || i >= buffer->h) return; 37 38 // this assumes the texture is rotated (otherwise it's slower due to cache missing) 39 // ((short *)buffer->line)[x] = (((short*)texture->line[xoff])[srcy] >> 1 & 0x7BEF); 40 ((short *)buffer->line)[x] = *texturePointer; 41 } 42 }

OpenLayer has reached a random SVN version number ;) | Online manual | Installation video!| MSVC projects now possible with cmake | Now alvailable as a Dev-C++ Devpack! (Thanks to Kotori)

23yrold3yrold
Member #1,134
March 2001

Quote:

which doesn't take in account that you're not starting the pixel rendering from the zero offset.

But I am atarting the pixel rendering from 0. The while loop is fine; it's the if statement gumming up the works. At first I thought you might be on to something setting y to something other than 0, but num is equal to the sub-pixel offset of the texel, so that should be okay. I think. Here's my most recent revision (which isn't a whole lot different than the last one, but I'll comment it) ...

 1 void DrawSlice(BITMAP* buffer, BITMAP* texture, const int xoff, const int x, int y, const int tall) 2 { 3 // step is for calculating srcy as the column is drawn 4 // srcy is the texture coordinate to be drawn 5 unsigned int step = 0; 6 unsigned int srcy = 0; 7 8 // skip down until we hit the top of the screen (for very close walls) 9 // this bit is currently a little buggy ... 10 if(y < 0) 11 { 12 step = 64 * -y; 13 14 if(step >= tall) 15 { 16 srcy = step / tall; 17 step = step & 63; 18 } 19 20 y = 0; 21 } 22 23 // draw that slice! 24 for(int i = y ; i < y + tall ; ++i) 25 { 26 step += 64; 27 28 // srcy is incremented relative to how tall the wall is 29 while(step >= tall) 30 { 31 step -= tall; 32 ++srcy; 33 } 34 35 // next line isn't really necessary unless I remove the troublesome if statement above ... 36 if(i < 0) continue; 37 if(srcy >= 64 || i >= buffer->h) return; 38 39 // this assumes the texture is rotated (otherwise it's slower due to cache missing) 40 ((short *)buffer->line)[x] = ((short*)texture->line[xoff])[srcy]; 41 } 42 }

I renamed 'num' to 'step' for clarity. 'num' was a holdover from the Bresenham function I modified for this

--
Software Development == Church Development
Step 1. Build it.
Step 2. Pray.

 Fladimir da Gorf Member #1,565 October 2001 OK, I didn't make it clear - I think you should subtract something from step before entering the loop. Looking at the screenshot it looks like if all the stretched pixels in the top of the screen are lined up.  Yeah, testing the code it seems the problem is that the y-coordinates get rounded down to the nearest texture pixel. OpenLayer has reached a random SVN version number ;) | Online manual | Installation video!| MSVC projects now possible with cmake | Now alvailable as a Dev-C++ Devpack! (Thanks to Kotori)
 23yrold3yrold Member #1,134 March 2001 Actually, I tried subtracting step from 64. But it didn't help --Software Development == Church DevelopmentStep 1. Build it.Step 2. Pray.
 Fladimir da Gorf Member #1,565 October 2001 And it seems that richard is right - if the wall is close enough, srcy will never be anything else than zero. OpenLayer has reached a random SVN version number ;) | Online manual | Installation video!| MSVC projects now possible with cmake | Now alvailable as a Dev-C++ Devpack! (Thanks to Kotori)
23yrold3yrold
Member #1,134
March 2001

I would probably buy this if you showed me some code that fixes it, since the texture coordinate is definitely not 0 (it's off by a little, not half the texture!)

EDIT: Bwa ha ha! That biotch is fixed!!

 1 void DrawSlice(BITMAP* buffer, BITMAP* texture, const int xoff, const int x, int y, const int tall) 2 { 3 unsigned int step = 0; 4 unsigned int srcy = 0; 5 6 // skip down until we hit the top of the screen (for very close walls) 7 // this bit is currently a little buggy ... 8 if(y < 0) 9 { 10 step = 64 * -y; 11 12 if(step >= tall) 13 { 14 srcy = step / tall; 15 step = step % tall; 16 } 17 18 y = 0; 19 } 20 21 // draw that slice! 22 for(int i = y ; i < y + tall ; ++i) 23 { 24 step += 64; 25 26 while(step >= tall) 27 { 28 step -= tall; 29 ++srcy; 30 } 31 32 if(i < 0) continue; 33 if(srcy >= 64 || i >= buffer->h) return; 34 35 // this assumes the texture is rotated (otherwise it's slower due to cache missing) 36 ((short *)buffer->line)[x] = ((short*)texture->line[xoff])[srcy]; 37 } 38 }

I was modulo'ing by 64 when I should have used tall. Now I just need to fix that little tiny unrelated texture artifact and I'm done! Woo-hoo!

--
Software Development == Church Development
Step 1. Build it.
Step 2. Pray.

 Fladimir da Gorf Member #1,565 October 2001 Strangely, if I comment out the following lines it seems to work smoothly: ```if(num >= tall) { srcy = num / tall; num &= 63; } ``` I don't know if commenting them out just ruins the whole idea, though. OpenLayer has reached a random SVN version number ;) | Online manual | Installation video!| MSVC projects now possible with cmake | Now alvailable as a Dev-C++ Devpack! (Thanks to Kotori)
 23yrold3yrold Member #1,134 March 2001 Quote:Strangely, if I comment out the following lines it seems to work smoothly:Yes, it does, but the idea is to skip offscreen pixels en masse. The while loop does it, but it's loads slower ...EDIT: Yeah, I didn't know for sure if %= was a valid operator --Software Development == Church DevelopmentStep 1. Build it.Step 2. Pray.
Fladimir da Gorf
Member #1,565
October 2001

If you change it to this, it seems to work as well:

```if(num >= tall)
{
srcy = num / tall;
num %= tall;  // Note this line //
}
```

I think it basically does the same thing as the while(num >= tall) -loop

 Finally, I ended up with the following code:

 1 void DrawSlice(BITMAP* buffer, BITMAP* texture, int xoff, int x, int y, int tall) 2 { 3 int srcy = 0, num = 0; 4 5 // skip down until we hit the top of the screen (for very close walls) 6 // this bit is currently a little buggy ... 7 if(y < 0) 8 { 9 num = 64 * -y; 10 11 if(num >= tall) 12 { 13 srcy = num / tall; 14 num %= tall; 15 } 16 17 y = 0; 18 } 19 20 textprintf( buffer, font, 0, 0, makecol( 255, 255, 255 ), "num %d srcy %d", num, srcy ); 21 22 // draw that slice! 23 // Added a pointer to the current texture pixel // 24 short *texturePointer = (short*)texture->line[xoff] + srcy; 25 for(int i = y ; i < y + tall ; ++i) 26 { 27 num += 64; 28 29 if(num >= tall) 30 { 31 int diff = num / tall; 32 srcy += diff; 33 texturePointer += diff; 34 num %= tall; 35 } 36 37 if(srcy >= 64 || i >= buffer->h) return; 38 39 // this assumes the texture is rotated (otherwise it's slower due to cache missing) 40 // ((short *)buffer->line)[x] = (((short*)texture->line[xoff])[srcy] >> 1 & 0x7BEF); 41 ((short *)buffer->line)[x] = *texturePointer; 42 } 43 }

Works damn fast.

OpenLayer has reached a random SVN version number ;) | Online manual | Installation video!| MSVC projects now possible with cmake | Now alvailable as a Dev-C++ Devpack! (Thanks to Kotori)

 Richard Phipps Member #1,632 November 2001 coughQuote:And it seems that richard is right - if the wall is close enough, srcy will never be anything else than zero. SMUG MODE: hehehehe! It must be my lucky day, I answered a maths question and got it right!
 Fladimir da Gorf Member #1,565 October 2001 23, I still think you should use my version instead OpenLayer has reached a random SVN version number ;) | Online manual | Installation video!| MSVC projects now possible with cmake | Now alvailable as a Dev-C++ Devpack! (Thanks to Kotori)
 23yrold3yrold Member #1,134 March 2001 My version works and has less code in that loop (which gets called for every wall pixel onscreen). And RP was not right ....Anyway, expect me to post again shortly about that last texture artifact if I can't lick it ... --Software Development == Church DevelopmentStep 1. Build it.Step 2. Pray.
 Fladimir da Gorf Member #1,565 October 2001 "less code in that loop"Which executes slower Especially the while loop thingy.EDIT: One more thing: if( srcy >= 64 ) is the same as if( srcy & 0x40 ) but slower... OpenLayer has reached a random SVN version number ;) | Online manual | Installation video!| MSVC projects now possible with cmake | Now alvailable as a Dev-C++ Devpack! (Thanks to Kotori)
 Richard Phipps Member #1,632 November 2001 ok, I was on the right track!
 23yrold3yrold Member #1,134 March 2001 Quote:Which executes slower Especially the while loop thingy.Sorry, I'm not the one with a divide. My code is much quicker for close walls, and for distant wall the drawing is minimal anyway; I'm getting over 100 fps under any circumstances now. I'll use that (srcy & 0x40) though EDIT: I tried your code; I lost 20 fps ... --Software Development == Church DevelopmentStep 1. Build it.Step 2. Pray.
 1   2   3  Go to: Allegro Development Installation, Setup & Configuration Allegro.cc Comments Off-Topic Ordeals The Depot Game Design & Concepts Programming Questions Recent Threads