Pages: 1
  Print  
Author Topic: GML: draw_sprite_tiled_area + draw_sprite_tiled_area_ext (Custom, not in GM)  (Read 13782 times)
Offline (Unknown gender) TheExDeus
Posted on: September 25, 2010, 12:58:45 pm

Developer
Joined: Apr 2008
Posts: 1860

View Profile
Notice: These functions are not in GM. They are just additional functions that could be useful to add. What they do is that they tile a sprite over selected region (which is a rectangle with x1,y1 top left corner and x2,y2 bottom left). It automatically crops the image as needed and it works with any size sprite. They are based on GMLScripts script http://www.gmlscripts.com/script/draw_sprite_tiled_area by EyeGuy.

Function: draw_sprite_tiled_area(int spr,int subimg,double x,double y,double x1,double y1,double x2,double y2);

GSsprite.h:
Code: [Select]
int draw_sprite_tiled_area(int spr,int subimg,double x,double y,double x1,double y1,double x2,double y2);
GSsprite.cpp:
Code: [Select]
int draw_sprite_tiled_area(int spr,int subimg,double x,double y,double x1,double y1,double x2,double y2)
{
  enigma::sprite *spr2d = enigma::spritestructarray[spr];
  if (!spr2d)
    return -1;

  if (enigma::cur_bou_tha_noo_sho_eve_cha_eve != spr2d->texturearray[subimg % spr2d->subcount])
  {
    glBindTexture(GL_TEXTURE_2D,spr2d->texturearray[subimg % spr2d->subcount]);
    enigma::cur_bou_tha_noo_sho_eve_cha_eve = spr2d->texturearray[subimg % spr2d->subcount];
  }


  glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_CLAMP);
  glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_CLAMP);


  glPushAttrib(GL_CURRENT_BIT);
    glColor4f(1,1,1,1);

    const float tbx=spr2d->texbordx,tby=spr2d->texbordy;
    float sw,sh,i,j,jj,left,top,width,height,X,Y;
    sw = spr2d->width;
    sh = spr2d->height;

    i = x1-(fmod(x1,sw) - fmod(x,sw)) - sw*(fmod(x1,sw)<fmod(x,sw));
    j = y1-(fmod(y1,sh) - fmod(y,sh)) - sh*(fmod(y1,sh)<fmod(y,sh));
    jj = j;

    glBegin(GL_QUADS);
    for(i=i; i<=x2; i+=sw) {
        for(j=j; j<=y2; j+=sh) {

            if(i <= x1) left = x1-i;
            else left = 0;
            X = i+left;

            if(j <= y1) top = y1-j;
            else top = 0;
            Y = j+top;

            if(x2 <= i+sw) width = ((sw)-(i+sw-x2)+1)-left;
            else width = sw-left;

            if(y2 <= j+sh) height = ((sh)-(j+sh-y2)+1)-top;
            else height = sh-top;

            glTexCoord2f(left/sw*tbx,top/sh*tby);
            glVertex2f(X,Y);
            glTexCoord2f((left+width)/sw*tbx,top/sh*tby);
            glVertex2f(X+width,Y);
            glTexCoord2f((left+width)/sw*tbx,(top+height)/sh*tby);
            glVertex2f(X+width,Y+height);
            glTexCoord2f(left/sw*tbx,(top+height)/sh*tby);
            glVertex2f(X,Y+height);
        }
        j = jj;
    }
    glEnd();

    glPopAttrib();
    return 0;
}

Function: draw_sprite_tiled_area_ext(int spr,int subimg,double x,double y,double x1,double y1,double x2,double y2, double xscale, double yscale, int color, double alpha);

GSsprite.h:
Code: [Select]
int draw_sprite_tiled_area_ext(int spr,int subimg,double x,double y,double x1,double y1,double x2,double y2, double xscale, double yscale, int color, double alpha);
GSsprite.cpp:
Code: [Select]
int draw_sprite_tiled_area_ext(int spr,int subimg,double x,double y,double x1,double y1,double x2,double y2, double xscale, double yscale, int color, double alpha)
{
  enigma::sprite *spr2d = enigma::spritestructarray[spr];
  if (!spr2d)
    return -1;

  if (enigma::cur_bou_tha_noo_sho_eve_cha_eve != spr2d->texturearray[subimg % spr2d->subcount])
  {
    glBindTexture(GL_TEXTURE_2D,spr2d->texturearray[subimg % spr2d->subcount]);
    enigma::cur_bou_tha_noo_sho_eve_cha_eve = spr2d->texturearray[subimg % spr2d->subcount];
  }


  glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_CLAMP);
  glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_CLAMP);


  glPushAttrib(GL_CURRENT_BIT);
    glColor4ub(__GETR(color),__GETG(color),__GETB(color),char(alpha*255));

    const float tbx=spr2d->texbordx,tby=spr2d->texbordy;
    float sw,sh,i,j,jj,left,top,width,height,X,Y;
    sw = spr2d->width*xscale;
    sh = spr2d->height*yscale;

    i = x1-(fmod(x1,sw) - fmod(x,sw)) - sw*(fmod(x1,sw)<fmod(x,sw));
    j = y1-(fmod(y1,sh) - fmod(y,sh)) - sh*(fmod(y1,sh)<fmod(y,sh));
    jj = j;

    glBegin(GL_QUADS);
    for(i=i; i<=x2; i+=sw) {
        for(j=j; j<=y2; j+=sh) {

            if(i <= x1) left = x1-i;
            else left = 0;
            X = i+left;

            if(j <= y1) top = y1-j;
            else top = 0;
            Y = j+top;

            if(x2 <= i+sw) width = ((sw)-(i+sw-x2)+1)-left;
            else width = sw-left;

            if(y2 <= j+sh) height = ((sh)-(j+sh-y2)+1)-top;
            else height = sh-top;

            glTexCoord2f(left/sw*tbx,top/sh*tby);
            glVertex2f(X,Y);
            glTexCoord2f((left+width)/sw*tbx,top/sh*tby);
            glVertex2f(X+width,Y);
            glTexCoord2f((left+width)/sw*tbx,(top+height)/sh*tby);
            glVertex2f(X+width,Y+height);
            glTexCoord2f(left/sw*tbx,(top+height)/sh*tby);
            glVertex2f(X,Y+height);
        }
        j = jj;
    }
    glEnd();

    glPopAttrib();
    return 0;
}

Added attachments show:
First image: draw_sprite_tiled_area(sprite0,0,0,0,75,75,375,375);
Second image: draw_sprite_tiled_area_ext(sprite0,0,0,0,75,75,375,375,0.5,0.5,c_yellow,0.7);

You can see some artifacts when scaled down, but I guess it is normal.
« Last Edit: September 26, 2010, 08:57:04 am by HaRRiKiRi » Logged
Offline (Male) Josh @ Dreamland
Reply #1 Posted on: October 16, 2010, 01:38:32 pm

Prince of all Goldfish
Developer
Location: Pittsburgh, PA, USA
Joined: Feb 2008
Posts: 2950

View Profile Email
I'm not sure what to do with the licensing for these. I can see these being useful, though. Is any license associated with them on that site?
Logged
"That is the single most cryptic piece of code I have ever seen." -Master PobbleWobble
"I disapprove of what you say, but I will defend to the death your right to say it." -Evelyn Beatrice Hall, Friends of Voltaire
Offline (Female) IsmAvatar
Reply #2 Posted on: October 16, 2010, 02:16:10 pm

LateralGM Developer
LGM Developer
Location: Pennsylvania/USA
Joined: Apr 2008
Posts: 877

View Profile Email
The scripts on that site are unlicensed and free use, but copyrighted. That means that technically you can steal them and license them however you'd like. However, it would be common courtesy to try to contact the author first and make sure that they are ok with you relicensing them to a GPL compatible license (such as MIT, or GPL)
Logged
Offline (Unknown gender) TheExDeus
Reply #3 Posted on: October 16, 2010, 04:58:57 pm

Developer
Joined: Apr 2008
Posts: 1860

View Profile
They are free to use, modify and redistribute, so there is really no license involved. You don't even have to give credit, but you could if you were kind enough. :D I do understand the math behind all this, so I could make them from scratch, but they would look almost exactly like these. Its just that there are aren't so many ways to invent the wheel... I could make them more messy and less optimized if you want. :D Then they would be custom made for sure. And I am pretty sure these can't be optimized any more, because gmlscript.com usually hold only the most optimized code. Thou here we could change float to int, thus creating an (substantial?) speed increase, because I don't see why width, height or position should be decimal.. Thou you have made all positions and sizes in all functions floats for some reason. I know that GM allows x and y to be a decimal, but I don't get why. You cant have something 1.5 pixels from somewhere. Its a lot better if is 1 or 2 pixels.

Hope you understand this post. It seems I have written a lot and said so little.
Logged
Offline (Male) Josh @ Dreamland
Reply #4 Posted on: October 17, 2010, 08:23:37 am

Prince of all Goldfish
Developer
Location: Pittsburgh, PA, USA
Joined: Feb 2008
Posts: 2950

View Profile Email
Well, that's a mistake in itself. You could have the most outstandingly efficient piece of GML fathomable, and on the optimization scale, it'd be a steaming pile of shit and rusted bolts compared to the equivalent in a real language. Not just because GM's interpreter is slow, but because GM's pointerless, classless system makes you do all sorts of running around to get something simple done. Compare a C Brainfuck interpreter to a JavaScript one. There's no comparison.

But yes, your purpose is legal, then; as Ism said, it's just common courtesy to let him know we're using them. (Even though I don't find anything particularly insightful about his code, it's the idea that counts). But, seeing as that site is full of people taking such scripts and running with them without credit, I suppose it'd only be annoying if everyone that found use for them emailed him. So do what you like.

Anyway, yes, I'm a proponent of integral coordinates. Except one thing:
All vars are double. To call your function, they are cast as int.
You then invoke glTexCoord2f, casting them back to float.

I do the same thing; I've been waiting for someone to help me decide what to do about it. I think at this point swapping them all for 2i would be our best bet.
« Last Edit: October 17, 2010, 08:26:17 am by Josh @ Dreamland » Logged
"That is the single most cryptic piece of code I have ever seen." -Master PobbleWobble
"I disapprove of what you say, but I will defend to the death your right to say it." -Evelyn Beatrice Hall, Friends of Voltaire
Offline (Female) IsmAvatar
Reply #5 Posted on: October 17, 2010, 09:07:32 am

LateralGM Developer
LGM Developer
Location: Pennsylvania/USA
Joined: Apr 2008
Posts: 877

View Profile Email
Quote
But, seeing as that site is full of people taking such scripts and running with them without credit, I suppose it'd only be annoying if everyone that found use for them emailed him. So do what you like.
Yes, but it's not every day that someone requests permission to relicense/license their code.
Logged
Offline (Male) Josh @ Dreamland
Reply #6 Posted on: October 17, 2010, 12:43:33 pm

Prince of all Goldfish
Developer
Location: Pittsburgh, PA, USA
Joined: Feb 2008
Posts: 2950

View Profile Email
Good point. Maybe I'll drop him a letter later.
Logged
"That is the single most cryptic piece of code I have ever seen." -Master PobbleWobble
"I disapprove of what you say, but I will defend to the death your right to say it." -Evelyn Beatrice Hall, Friends of Voltaire
Offline (Male) Brett
Reply #7 Posted on: October 19, 2010, 07:34:48 pm

Member
Location: Canada!
Joined: Aug 2010
Posts: 25

View Profile Email
Thou here we could change float to int, thus creating an (substantial?) speed increase, because I don't see why width, height or position should be decimal.. Thou you have made all positions and sizes in all functions floats for some reason. I know that GM allows x and y to be a decimal, but I don't get why. You cant have something 1.5 pixels from somewhere. Its a lot better if is 1 or 2 pixels.
GM allows X,Y to be decimals because you can modify the view so that those little differences matter. GM has 3D support, and all 2D functions work in 3D as well so the decimals matter when the view is transformed.



[EDIT]
Not sure if you can do this in OpenGL (I've only used DX) but you can get DX to do this automatically for you. Simply turn texture repeating on and then put a vertex at the 4 corners with texture cords changed.
[/EDIT]

[EDIT2]
Something like this? (Never used OGL before, so it needs debugging)

.H file
Code: [Select]
int draw_sprite_tiled_area(int spr, double X, double Y, int x1, int y1, int x2, int y2);
.CPP file
Code: [Select]
//int spr, double x, double y, int x1, int y1, int x2, int y2
//Draws a rectangle between [x1,y1] and [x2,y2] with the sprite offset by X and Y (both 0-1)
int draw_sprite_tiled_area(int spr, double X, double Y, int x1, int y1, int x2, int y2){
  enigma::sprite *spr2d = enigma::spritestructarray[spr];
  //Non existant sprite
  if (!spr2d) return -1;
  //Some error? No idea, but it is used in the above example too.
  if (enigma::cur_bou_tha_noo_sho_eve_cha_eve != spr2d->texturearray[subimg % spr2d->subcount]){
    glBindTexture(GL_TEXTURE_2D,spr2d->texturearray[subimg % spr2d->subcount]);
    enigma::cur_bou_tha_noo_sho_eve_cha_eve = spr2d->texturearray[subimg % spr2d->subcount];
  }
  const float tbx=spr2d->texbordx;
  const float tby=spr2d->texbordy;
  const float sw = spr2d->width;
  const float sh = spr2d->height;
  //Texture repeat ON
  glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_REPEAT);
  glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_REPEAT);
  glPushAttrib(GL_CURRENT_BIT);
  glColor4f(1,1,1,1);
  //Draw the quad
  glBegin(GL_QUADS);
       glTexCoord2f(x1/sw*tbx+X,y1/sh*tby+Y);
       glVertex2f(x1,y1);
       glTexCoord2f(x2/sw*tbx+X,y1/sh*tby+Y);
       glVertex2f(x2,y1);
       glTexCoord2f(x2/sw*tbx+X,y2/sh*tby+Y);
       glVertex2f(x1,y2);
       glTexCoord2f(x1/sw*tbx+X,y2/sh*tby+Y);
       glVertex2f(x2,y2);
  //End drawing
  glEnd();
  glPopAttrib();
  return 0;
}

No credit required and No license attached - do whatever you want with it (if it works). Derived from the code above
[/EDIT2]
« Last Edit: October 19, 2010, 08:25:55 pm by Brett » Logged
GML Programmer Since 2005, C++ Programmer Since 2009
Offline (Male) RetroX
Reply #8 Posted on: October 20, 2010, 02:30:28 pm

Master of all things Linux
Contributor
Location: US
Joined: Apr 2008
Posts: 1055
MSN Messenger - classixretrox@gmail.com
View Profile Email
If numbers are stored as doubles, and passed as doubles, why are you using glVertex2f instead of glVertex2d?
Logged
My Box: Phenom II 3.4GHz X4 | ASUS ATI RadeonHD 5770, 1GB GDDR5 RAM | 1x4GB DDR3 SRAM | Arch Linux, x86_64 (Cube) / Windows 7 x64 (Blob)
Quote from: Fede-lasse
Why do all the pro-Microsoft people have troll avatars? :(
Offline (Male) Josh @ Dreamland
Reply #9 Posted on: October 20, 2010, 08:07:51 pm

Prince of all Goldfish
Developer
Location: Pittsburgh, PA, USA
Joined: Feb 2008
Posts: 2950

View Profile Email
Brett--
You are assuming all power-of-two textures. I see you multiplied tbx and tby by the necessary factor. Those variables, however, are only 1 (meaning the edge of the sprite) when the sprite is a power of two across both dimensions. I proposed such a fix after the check for each against 1, but no one has implemented it, yet.

Also, can you elaborate on a circumstance where doubles would be necessary for X and Y for the sake of accuracy? I'm not sure if a highly zoomed in view would produce such a case or not; can you test that for me? (I realize that many GL demonstrations have axises from -1 to 1, but I am not sure what GM's behavior would be in that case.)

RetroX--
No good reason. Originally I was using floats for x and y, but then I changed to doubles, and now I'm using int. I never updated the code, though, because I was waiting for someone like Brett to justify why they should be doubles.
Logged
"That is the single most cryptic piece of code I have ever seen." -Master PobbleWobble
"I disapprove of what you say, but I will defend to the death your right to say it." -Evelyn Beatrice Hall, Friends of Voltaire
Offline (Unknown gender) TheExDeus
Reply #10 Posted on: October 21, 2010, 01:49:04 pm

Developer
Joined: Apr 2008
Posts: 1860

View Profile
So whens the new Rep coming? I want to study a code a bit and maybe, in time, I could add more advanced things (thinking about paths). Just want to have the newest rep before I do so.
Logged
Pages: 1
  Print