Allegro.cc - Online Community

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

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

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

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?

1void 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<i>)[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?

1DrawSlice(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&&i<SCREENHEIGHT)
21 {
22 ((short *)buffer->line<i>)[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
avatar

if(tall > SCREENHEIGHT)
Shouldn't that be:

if(y + tall > SCREENHEIGHT)

?

--
- Bob
[ -- All my signature links are 404 -- ]

23yrold3yrold
Member #1,134
March 2001
avatar

Bob: same diff.

   y == (tall - SCREENHEIGHT) / 2

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

1void 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<i>)[x] = (((short*)texture->line[xoff])[srcy] >> 1 & 0x7BEF);
36 ((short *)buffer->line<i>)[x] = ((short*)texture->line[xoff])[srcy];
37 }
38}

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

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

Richard Phipps
Member #1,632
November 2001
avatar

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
avatar

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 Development
Step 1. Build it.
Step 2. Pray.

Richard Phipps
Member #1,632
November 2001
avatar

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
avatar

No difference at all; sorry :)

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

Richard Phipps
Member #1,632
November 2001
avatar

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
avatar

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:

1void 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<i>)[x] = (((short*)texture->line[xoff])[srcy] >> 1 & 0x7BEF);
40 ((short *)buffer->line<i>)[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
avatar

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) ...

1void 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<i>)[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
avatar

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.

[edit] 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
avatar

Actually, I tried subtracting step from 64. But it didn't help :P

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

Fladimir da Gorf
Member #1,565
October 2001
avatar

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
avatar

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!!

1void 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<i>)[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
avatar

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
avatar

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 Development
Step 1. Build it.
Step 2. Pray.

Fladimir da Gorf
Member #1,565
October 2001
avatar

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

[edit] Finally, I ended up with the following code:

1void 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<i>)[x] = (((short*)texture->line[xoff])[srcy] >> 1 & 0x7BEF);
41 ((short *)buffer->line<i>)[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
avatar

cough

Quote:

And it seems that richard is right - if the wall is close enough, srcy will never be anything else than zero.

SMUG MODE: ;D

hehehehe! It must be my lucky day, I answered a maths question and got it right! ;)

Fladimir da Gorf
Member #1,565
October 2001
avatar

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
avatar

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 Development
Step 1. Build it.
Step 2. Pray.

Fladimir da Gorf
Member #1,565
October 2001
avatar

"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
avatar

23yrold3yrold
Member #1,134
March 2001
avatar

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 Development
Step 1. Build it.
Step 2. Pray.

 1   2   3 


Go to: