ENIGMA Forums

Contributing to ENIGMA => Function Peer Review => Topic started by: TheExDeus on September 10, 2010, 05:59:44 am

Title: GML: draw_sprite_tiled + draw_sprite_tiled_ext (works only with power of two)
Post by: TheExDeus on September 10, 2010, 05:59:44 am
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 (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.
Title: Re: GML: draw_sprite_tiled + draw_sprite_tiled_ext (unfinished)
Post by: Josh @ Dreamland on September 10, 2010, 12:10:32 pm
'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?
Title: Re: GML: draw_sprite_tiled + draw_sprite_tiled_ext (unfinished)
Post by: TheExDeus on September 10, 2010, 02:30:46 pm
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.
Title: Re: GML: draw_sprite_tiled + draw_sprite_tiled_ext (unfinished)
Post by: Josh @ Dreamland on September 10, 2010, 02:45:18 pm
 Works for me. I figure at some point I'll have to break down and add an if() for it, anyway.
Title: Re: GML: draw_sprite_tiled + draw_sprite_tiled_ext (unfinished)
Post by: serprex on September 11, 2010, 12:38:20 pm
char(alpha*255) is undefined if alpha is above 0.5 or below 0
Title: Re: GML: draw_sprite_tiled + draw_sprite_tiled_ext (unfinished)
Post by: TheExDeus on September 11, 2010, 12:52:32 pm
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.
Title: Re: GML: draw_sprite_tiled + draw_sprite_tiled_ext (works only with power of two)
Post by: MrGriggs on January 10, 2011, 10:11:10 am
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.
Title: Re: GML: draw_sprite_tiled + draw_sprite_tiled_ext (works only with power of two)
Post by: TheExDeus on January 10, 2011, 10:27:28 am
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.
Title: Re: GML: draw_sprite_tiled + draw_sprite_tiled_ext (works only with power of two)
Post by: MrGriggs on January 10, 2011, 10:40:36 am
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.
Title: Re: GML: draw_sprite_tiled + draw_sprite_tiled_ext (works only with power of two)
Post by: Josh @ Dreamland on January 11, 2011, 12:58:24 pm
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
Title: Re: GML: draw_sprite_tiled + draw_sprite_tiled_ext (works only with power of two)
Post by: TheExDeus on January 11, 2011, 03:19:14 pm
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
Title: Re: GML: draw_sprite_tiled + draw_sprite_tiled_ext (works only with power of two)
Post by: Josh @ Dreamland on January 11, 2011, 03:25:40 pm
I don't know why it's doing that if you're specifying the whole screen as the rectangle.
Title: Re: GML: draw_sprite_tiled + draw_sprite_tiled_ext (works only with power of two)
Post by: MrGriggs on January 12, 2011, 07:58:02 am
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.
Title: Re: GML: draw_sprite_tiled + draw_sprite_tiled_ext (works only with power of two)
Post by: Josh @ Dreamland on January 12, 2011, 10:39:30 am
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 {}.

Title: Re: GML: draw_sprite_tiled + draw_sprite_tiled_ext (works only with power of two)
Post by: MrGriggs on January 12, 2011, 10:53:18 am
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