Pages: [1]
  Print  
Author Topic: GML: draw_sprite_tiled + draw_sprite_tiled_ext (works only with power of two)  (Read 4323 times)
Offline (Unknown gender) TheExDeus
Posted on: September 10, 2010, 05:59:44 AM

Developer
Joined: Apr 2008
Posts: 1914

View Profile
Notice: These functions work only with power of two textures (sprites), so this implementation is kind of limited. Also, it will only draw a tiled region with width/height the length of min(room_width,room_height). This is OpenGL limitation. Still, this could be used for something, and I think tiling power of two images this way is much faster than the other way (http://enigma-dev.org/forums/index.php?topic=641.0), but that way doesn't have any limitations.

Function: draw_sprite_tiled(int spr,int subimg,double x,double y);

GSsprite.h:
Code: [Select]
int draw_sprite_tiled(int spr,int subimg,double x,double y);
GSsprite.cpp:
Code: [Select]
int draw_sprite_tiled(int spr,int subimg,double x,double y)
{
  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_REPEAT);
  glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_REPEAT);


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

    const float tbx=spr2d->texbordx,tby=spr2d->texbordy,
        vertil=room_width/spr2d->width,
        hortil=room_height/spr2d->height,
        xoff=spr2d->xoffset/spr2d->width+x/spr2d->width,
        yoff=spr2d->yoffset/spr2d->height+y/spr2d->height;
    glBegin(GL_QUADS);
      glTexCoord2f(xoff,yoff);
        glVertex2f(0,0);
      glTexCoord2f(hortil*tbx+xoff,yoff);
        glVertex2f(spr2d->width*hortil,0);
      glTexCoord2f(hortil*tbx+xoff,vertil*tby+yoff);
        glVertex2f(spr2d->width*hortil,spr2d->height*vertil);
      glTexCoord2f(xoff,vertil*tby+yoff);
        glVertex2f(0,spr2d->height*vertil);
    glEnd();

    glPopAttrib();
    return 0;
}

Function:draw_sprite_tiled_ext(int spr,int subimg,double x,double y,double xscale,double yscale,int color,double alpha);

GSsprite.h:
Code: [Select]
int draw_sprite_tiled_ext(int spr,int subimg,double x,double y,double xscale,double yscale,int color,double alpha);
GSsprite.cpp:
Code: [Select]
int draw_sprite_tiled_ext(int spr,int subimg,double x,double y,double xscale,double yscale,int blend,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_REPEAT);
  glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_REPEAT);


  glPushAttrib(GL_CURRENT_BIT);
    //glColor4f(1,1,1,1);
    glColor4ub(__GETR(blend),__GETG(blend),__GETB(blend),char(alpha*255));
    const float tbx=spr2d->texbordx,tby=spr2d->texbordy,
        vertil=room_width/(spr2d->width*xscale),
        hortil=room_height/(spr2d->height*yscale),
        xoff=spr2d->xoffset/(spr2d->width*xscale)+x/(spr2d->width*xscale),
        yoff=spr2d->yoffset/(spr2d->height*yscale)+y/(spr2d->height*yscale);
    glBegin(GL_QUADS);
      glTexCoord2f(xoff,yoff);
        glVertex2f(0,0);
      glTexCoord2f(hortil*tbx+xoff,yoff);
        glVertex2f(spr2d->width*xscale*hortil,0);
      glTexCoord2f(hortil*tbx+xoff,vertil*tby+yoff);
        glVertex2f(spr2d->width*xscale*hortil,spr2d->height*yscale*vertil);
      glTexCoord2f(xoff,vertil*tby+yoff);
        glVertex2f(0,spr2d->height*yscale*vertil);
    glEnd();

    glPopAttrib();
    return 0;
}

TO-DO:
1) Make both functions work in views (now they use room size)
2) Tile the tiled images. Now it draws as a square which has side as min(room_width, room_height). Maybe someone more profound in C++ could help with this.
« Last Edit: September 25, 2010, 04:53:23 PM by HaRRiKiRi » Logged
Offline (Male) Josh @ Dreamland
Reply #1 Posted on: September 10, 2010, 12:10:32 PM

Prince of all Goldfish
Developer
Location: Ohio, United States
Joined: Feb 2008
Posts: 2946

View Profile Email
'fraid I have to deny those. They're unimplemented for a reason. Create a 48*48 sprite and try your functions; you won't like the results. But for power-of-two textures, that will work fine. See the issue?
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 #2 Posted on: September 10, 2010, 02:30:46 PM

Developer
Joined: Apr 2008
Posts: 1914

View Profile
Ou I see. Didn't check for non ^2 sprites. Actually, I did want to make this function in another way (which is a lot slower, that is why in the end I did this). The slower way would be to just draw individual textures in a for loop (two for loops, or repeat or whatever). Thou this would just be like doing it the same in LGM with draw_sprite, so I guess its redundant. Anyway, I will look into backgrounds when all of the basic framework is there.
Logged
Offline (Male) Josh @ Dreamland
Reply #3 Posted on: September 10, 2010, 02:45:18 PM

Prince of all Goldfish
Developer
Location: Ohio, United States
Joined: Feb 2008
Posts: 2946

View Profile Email
 Works for me. I figure at some point I'll have to break down and add an if() for it, anyway.
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) serprex
Reply #4 Posted on: September 11, 2010, 12:38:20 PM
Smooth ER
Developer
Joined: Apr 2008
Posts: 106

View Profile WWW
char(alpha*255) is undefined if alpha is above 0.5 or below 0
Logged
Offline (Unknown gender) TheExDeus
Reply #5 Posted on: September 11, 2010, 12:52:32 PM

Developer
Joined: Apr 2008
Posts: 1914

View Profile
All other sprite functions use the same for alpha. But anyway, as this method doesn't really work, and as this function is almost never used, then I don't see any reason to continue this. I will wait until Josh creates framework for backgrounds and then I will add functions for that.
Logged
Offline (Unknown gender) MrGriggs
Reply #6 Posted on: January 10, 2011, 10:11:10 AM

Member
Joined: Dec 2010
Posts: 128

View Profile Email
In my opinion being able to draw sprites in this method would be great, and should be implemetned, I for one need it for my RTS.
Logged
Offline (Unknown gender) TheExDeus
Reply #7 Posted on: January 10, 2011, 10:27:28 AM

Developer
Joined: Apr 2008
Posts: 1914

View Profile
Quote
In my opinion being able to draw sprites in this method would be great, and should be implemetned, I for one need it for my RTS.
What exactly do you need from this method? As I already stated in the first post, this is very limited. Not only it works specifically with power of two textures alone, but also the maximum size you can draw it is min(window_width,window_height). So with a 800x600 you will get only a 600x600 region. So I think its better to use the other method already implemented. That method is also not slow, and the speed should not be a problem.
Logged
Offline (Unknown gender) MrGriggs
Reply #8 Posted on: January 10, 2011, 10:40:36 AM

Member
Joined: Dec 2010
Posts: 128

View Profile Email
I meant having a direct link to the alternate method via the (draw_sprite_texture) function call.

Would you be able to give me the code for the alternate function, please.
Logged
Offline (Male) Josh @ Dreamland
Reply #9 Posted on: January 11, 2011, 12:58:24 PM

Prince of all Goldfish
Developer
Location: Ohio, United States
Joined: Feb 2008
Posts: 2946

View Profile Email
I don't think two branches are unreasonable.

HaRRi, note two things. First, tbx and tby are both 1 for Po2 textures. Second, I believe the most efficient way to code this function is by giving it this structure:

Code: (C) [Select]
if (tbx == 1)
  if (tby == 1)
    //YOUR CURRENT METHOD
  else
    //DRAW LARGE TILED HORIZONTAL STRIPS OF SIZE REQUESTED_WIDTH * SPRITE_HEIGHT
else
  if (tby == 1)
    //DRAW LARGE TILED VERTICAL STRIPS OF SIZE SPRITE_WIDTH * REQUESTED_HEIGHT
  else
    //THE INEFFICIENT METHOD
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: January 11, 2011, 03:19:14 PM

Developer
Joined: Apr 2008
Posts: 1914

View Profile
Quote
First, tbx and tby are both 1 for Po2 textures.
I am aware.

But as I stated. (GL_TEXTURE_WRAP_S,GL_REPEAT) draws only the min(window_width,window_height). Maybe there is another parameter that needs to be changed, but for now I can't see any way to fix this. For example, I added a picture on how draw_sprite_tiled_n2 draws. It should tile the whole room, but it tiles a square of 480x480.

Quote
Second, I believe the most efficient way to code this function is by giving it this structure:
Well keeping the second thing in mind it should be:
Code: [Select]
max_size = min(window_width,window_height)
if (tbx == 1 && region_width < max_size)
  if (tby == 1 && region_height < max_size)
    //YOUR CURRENT METHOD
  else if (region_width < max_size)
    //DRAW LARGE TILED HORIZONTAL STRIPS OF SIZE REQUESTED_WIDTH * SPRITE_HEIGHT
else
  if (tby == 1 && region_height < max_size)
    //DRAW LARGE TILED VERTICAL STRIPS OF SIZE SPRITE_WIDTH * REQUESTED_HEIGHT
  else
    //THE INEFFICIENT METHOD
Logged
Offline (Male) Josh @ Dreamland
Reply #11 Posted on: January 11, 2011, 03:25:40 PM

Prince of all Goldfish
Developer
Location: Ohio, United States
Joined: Feb 2008
Posts: 2946

View Profile Email
I don't know why it's doing that if you're specifying the whole screen as the rectangle.
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) MrGriggs
Reply #12 Posted on: January 12, 2011, 07:58:02 AM

Member
Joined: Dec 2010
Posts: 128

View Profile Email
Create event
Code: [Select]
completetile=false

draw event
Code: [Select]
switch (completetile){

 case completetile = false:

  for (i=0;i*sprite_width<x-x2;i+=1){

   draw_sprite(sprite_index,-1,x+i*sprite_width,y+dropline*sprite_height)



    if i*sprite_width = x-x2{if dropline-1*sprite_height<y-y2 {dropline+=1;exit;}
    else {completetile = true; exit;}}

}


 break;

}

would anybody be able to tell me if this works, or why it doesn't, or give me a method that does, not at a compiler currently to test it, just wrote it off the top of my head.
Logged
Offline (Male) Josh @ Dreamland
Reply #13 Posted on: January 12, 2011, 10:39:30 AM

Prince of all Goldfish
Developer
Location: Ohio, United States
Joined: Feb 2008
Posts: 2946

View Profile Email
I have yet to implement switch(), but there are multiple problems with that code in any case, namely,
1) The point of a switch statement is to allow jumping to a piece of code marked by the correct value. So, "case varname==0" is pointless. Just "case 0" will suffice
2) The point of a switch statement is to quickly decode one value as a set of multiple values. So, "switch(boolean)" is, before optimization, less efficient than if (boolean) {} else {}.

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) MrGriggs
Reply #14 Posted on: January 12, 2011, 10:53:18 AM

Member
Joined: Dec 2010
Posts: 128

View Profile Email
I have yet to implement switch(), but there are multiple problems with that code in any case, namely,
1) The point of a switch statement is to allow jumping to a piece of code marked by the correct value. So, "case varname==0" is pointless. Just "case 0" will suffice
2) The point of a switch statement is to quickly decode one value as a set of multiple values. So, "switch(boolean)" is, before optimization, less efficient than if (boolean) {} else {}.
I know already what you're saying, sorry, I put the switch in there for another reason I've yet to utilize... sorry for confusion
Logged
Pages: [1]
  Print