Jibble

Author Topic: Drawing on screen (PLUGIN) [SOLVED]  (Read 394 times)

Dualnames

  • AGS Baker
  • Pretty Badass
    • Dualnames worked on one or more games that won an AGS Award!
    •  
    • Dualnames worked on one or more games that was nominated for an AGS Award!
Drawing on screen (PLUGIN) [SOLVED]
« on: 12 Feb 2019, 21:10 »
Code: Adventure Game Studio
  1. //WIND ENGINE
  2.  
  3. struct Particle{
  4. int x;
  5. int y;
  6. int transp;
  7. int life;
  8. bool active;
  9. int dx;
  10. int dy;
  11. int mlay;
  12. int timlay;
  13. int movedport;
  14. int translay;
  15. int translayHold;
  16. int width;
  17. int height;
  18. int fx;
  19. int fy;
  20. bool doingcircle;
  21. float angle;
  22. float radius;
  23. int doingCircleChance;
  24. int angleLay;
  25. int frame;
  26. float anglespeed;
  27. };
  28.  
  29. Particle particles[110];
  30. Particle particlesF[10];
  31. int WForceX[110];
  32. int WForceY[110];
  33.  
  34. int raysizeF=4;
  35. int dsizeF=0;
  36. int raysize=100;
  37. int dsize=0;
  38. int creationdelay=0;
  39. int creationdelayf=0;
  40. bool found_Activeparticle=false;
  41.  
  42. int32 Random(int value)
  43. {
  44.         return (rand() % value);
  45. }
  46.  
  47. void CreateParticle(int xx, int yy, int ForceX, int ForceY)
  48. {
  49.   int h=0;
  50.   bool foundparticle=false;
  51.   int fid=-1;
  52.   while (h <= dsize && !foundparticle)
  53.   {
  54.     if (particles[h].active==false)
  55.     {
  56.       foundparticle=true;
  57.       fid=h;
  58.     }
  59.     h++;
  60.   }
  61.  
  62.   if (foundparticle)
  63.   {
  64.     int d=fid;
  65.     particles[d].x=xx;
  66.     particles[d].y=yy;
  67.     particles[d].dx=0;
  68.     particles[d].dy=0;
  69.     particles[d].life=20000;
  70.     particles[d].transp=55+Random(10);
  71.     particles[d].active=true;
  72.     particles[d].mlay=4+Random(2);
  73.     particles[d].timlay=0;
  74.     particles[d].translay=0;
  75.     particles[d].translayHold=19+Random(15);
  76.     particles[d].width=2+Random(2);
  77.     particles[d].height=particles[d].width;
  78.     particles[d].fx=0;
  79.     particles[d].fy=0;
  80.     particles[d].doingcircle=false;
  81.     particles[d].angle=0.0;
  82.     particles[d].radius=4.0+float(Random(6));
  83.     particles[d].doingCircleChance=Random(200);
  84.     particles[d].angleLay=0;
  85.     particles[d].frame=0;
  86.     particles[d].anglespeed=float(Random(20))/100.0;
  87.     WForceX[d]=ForceX;
  88.     WForceY[d]=ForceY;
  89.     if (dsize<(raysize-1)) dsize++;
  90.   }
  91. }
  92.  
  93.  
  94.  
  95. void CreateParticleF(int xx, int yy, int ForceX, int ForceY)
  96. {
  97.   int h=0;
  98.   bool foundparticle=false;
  99.   int fid=-1;
  100.   while (h <= dsizeF && !foundparticle)
  101.   {
  102.     if (particlesF[h].active==false)
  103.     {
  104.       foundparticle=true;
  105.       fid=h;
  106.     }
  107.     h++;
  108.   }
  109.  
  110.   if (foundparticle)
  111.   {
  112.     int d=fid;
  113.     particlesF[d].x=xx;
  114.     particlesF[d].y=yy;
  115.     particlesF[d].dx=(-1)+Random(1);
  116.     particlesF[d].dy=(-1)+Random(1);
  117.     particlesF[d].life=20000;
  118.     particlesF[d].transp=45+Random(10);
  119.     particlesF[d].active=true;
  120.     particlesF[d].mlay=4+Random(2);
  121.     particlesF[d].timlay=0;
  122.     particlesF[d].translay=0;
  123.     particlesF[d].translayHold=19+Random(15);
  124.     particlesF[d].width=8+Random(2);
  125.     particlesF[d].height=particlesF[d].width;
  126.     particlesF[d].fx=0;
  127.     particlesF[d].fy=0;
  128.     particlesF[d].doingcircle=false;
  129.     particlesF[d].angle=0.0;
  130.     particlesF[d].radius=4.0+float(Random(6));
  131.     particlesF[d].doingCircleChance=Random(200);
  132.     particlesF[d].angleLay=0;
  133.     WForceX[d+100]=ForceX;
  134.     WForceY[d+100]=ForceY;
  135.     particlesF[d].frame=0;
  136.    
  137.    
  138.     if (dsizeF<(raysizeF-1)) dsizeF++;
  139.   }
  140. }
  141.  
  142. //WIND ENGINE
  143.  
  144. ///WING ENGINE UPDATE
  145. void ParticleUpdate(int ForceX, int ForceY, int Transparency,int RoomWidth,int RoomHeight)
  146. {
  147.  
  148.   int ww=RoomWidth;
  149.   int hh=RoomHeight;
  150.   BITMAP* screen = engine->GetVirtualScreen();
  151.  
  152.   found_Activeparticle=false;
  153.   creationdelay+=int(2.0);
  154.   if (creationdelay > 0)
  155.   {  
  156.    
  157.     int by=0;
  158.     while (by <2)
  159.     {
  160.     int dnx=Random(ww+250)-250;
  161.     int dny=Random(hh);    
  162.     CreateParticle(dnx, dny, ForceX, ForceY);
  163.     by++;
  164.     }
  165.    
  166.     int dnx=-(20+Random(50));
  167.     if (dnx<-160) dnx=-160;
  168.     if (dnx > ww+160) dnx=ww+160;
  169.    
  170.     int dny=Random(hh);    
  171.     CreateParticleF(dnx, dny, ForceX, ForceY);
  172.    
  173.     found_Activeparticle=true;
  174.    
  175.     creationdelay=0;
  176.   }
  177.  
  178.   int h=dsize-1;
  179.  
  180.   if (h < dsizeF-1)
  181.   {
  182.     h=dsizeF-1;
  183.   }
  184.   while (h>0)
  185.   {
  186.     if (particles[h].life>0)
  187.     {
  188.       found_Activeparticle=true;
  189.       particles[h].life-=int(2.0);
  190.       particles[h].doingCircleChance-=1;
  191.       int df=100-particles[h].transp;
  192.       df=10-(df/4);
  193.       int pwidth=particles[h].width+df;
  194.       int pheight=particles[h].height+df;
  195.      
  196.       int px=particles[h].x-(pwidth/2);
  197.       int py=particles[h].y-(pheight/2);
  198.       int tp=particles[h].transp+Transparency;
  199.      
  200.       if (tp>100) tp=100;
  201.      
  202.       int pgraph=0;
  203.       int SplitBetweenTwo=Random(100);
  204.       if (SplitBetweenTwo<=50) pgraph=813;
  205.       else pgraph=4466;
  206.      
  207.       if (tp!=100)
  208.           {
  209.                   BITMAP* ParticleGraph = engine->GetSpriteGraphic(pgraph+particles[h].frame);
  210.                   engine->BlitSpriteTranslucent(px, py, ParticleGraph,tp);
  211.                   //drawt.DrawImage(px, py, pgraph+particles[h].frame, tp, pwidth, pheight);
  212.           }
  213.       particles[h].timlay+=int(4.0);
  214.       if (particles[h].timlay> particles[h].mlay)
  215.       {
  216.         particles[h].frame++;
  217.         if (particles[h].frame>6) particles[h].frame=0;
  218.         particles[h].timlay=0;
  219.         particles[h].x += particles[h].dx+particles[h].fx;
  220.         particles[h].y += particles[h].dy+particles[h].fy;      
  221.       }
  222.       particles[h].translay+=1;
  223.       if (particles[h].translay>=particles[h].translayHold)
  224.       {
  225.         if (particles[h].transp<=99) particles[h].transp++;
  226.         else
  227.         {
  228.           particles[h].life=0;
  229.           found_Activeparticle=false;
  230.         }
  231.       }
  232.       if (particles[h].x>=ww-90 || particles[h].x<90)
  233.       {
  234.         if (particles[h].transp<=99)particles[h].transp++;
  235.         else
  236.         {
  237.           found_Activeparticle=false;
  238.           particles[h].life=0;      
  239.         }
  240.       }
  241.      
  242.       if (!particles[h].doingcircle && particles[h].angle==0.0
  243.       && particles[h].doingCircleChance<=0)
  244.       {
  245.         particles[h].doingcircle=true;
  246.       }
  247.       if (particles[h].doingcircle)
  248.       {
  249.         particles[h].angleLay+=(1+WForceX[h]);
  250.         if (particles[h].angleLay> 12)
  251.         {
  252.           particles[h].angleLay=0;
  253.           particles[h].angle+=particles[h].anglespeed;
  254.           int Y=particles[h].y + int((sin(particles[h].angle)* particles[h].radius));
  255.           int X=particles[h].x + int((cos(particles[h].angle)* particles[h].radius));
  256.           particles[h].x=X;
  257.           particles[h].y=Y;  
  258.         }
  259.       }
  260.       particles[h].fx=ForceX;
  261.       particles[h].fy=ForceY;
  262.      
  263.     }
  264.     else
  265.     {
  266.       particles[h].active=false;
  267.     }
  268.    
  269.    
  270.    
  271.     if (h<=9 && particlesF[h].life>0)
  272.     {
  273.       found_Activeparticle=true;
  274.       int pwidth=particlesF[h].width;
  275.       int pheight=particlesF[h].height;
  276.       int px=particlesF[h].x-(pwidth/2);
  277.       int py=particlesF[h].y-(pheight/2);
  278.       int pgraph=0;
  279.       int SplitBetweenTwo=Random(100);
  280.       if (SplitBetweenTwo<=50) pgraph=806;
  281.       else pgraph=4459;
  282.      
  283.       int tp=particlesF[h].transp+Transparency;      
  284.       if (tp>100) tp=100;
  285.      
  286.      
  287.       if (tp!=100)
  288.           {
  289.                   BITMAP* Particle_B = engine->GetSpriteGraphic(pgraph+particlesF[h].frame);
  290.                   engine->BlitSpriteTranslucent(px, py, Particle_B,tp);
  291.                   //drawt2.DrawImage(px, py, pgraph+particlesF[h].frame, tp, pwidth, pheight);
  292.           }
  293.       particlesF[h].timlay+=int(4.0);
  294.       if (particlesF[h].timlay> particlesF[h].mlay)
  295.       {
  296.         particlesF[h].frame++;
  297.         if (particlesF[h].frame>6)  particlesF[h].frame=0;
  298.         particlesF[h].timlay=0;
  299.         particlesF[h].x += particlesF[h].dx + ForceX;
  300.         particlesF[h].y += particlesF[h].dy + ForceY;  
  301.       }
  302.      
  303.      
  304.       if (particlesF[h].x>=ww-90 || particlesF[h].x<90)
  305.       {
  306.         particlesF[h].translay+=1;
  307.         if (particlesF[h].translay>=particlesF[h].translayHold)
  308.         {          
  309.           if (particlesF[h].transp<=99) particlesF[h].transp++;
  310.           else
  311.           {
  312.             found_Activeparticle=false;
  313.             particlesF[h].life=0;
  314.           }
  315.         }
  316.       }      
  317.     }
  318.     else
  319.     {
  320.       if (h<=9)  particlesF[h].active=false;
  321.     }
  322.    
  323.    
  324.     h--;
  325.   }
  326.   engine->ReleaseBitmapSurface(screen);
  327.  
  328. }
  329.  
  330. //WIND ENGINE UPDATE
  331.  


Nothing seems to be drawing on the screen, on my AGS script side i just run ParticleUpdate(int ForceX, int ForceY, int Transparency,int RoomWidth,int RoomHeight).
This is 'replacement' code moved from AGS to the plugin, so the code itself works fine. Any thoughts on why it doesn't? I'm not sure I'm using the 'virtual screen' part correctly, but there's little to no examples, I could find for it. Apologies for the sequence of new posts every day.
« Last Edit: 13 Feb 2019, 00:08 by Dualnames »
No more military army stuff. I'm alive and back.

Re: Drawing on screen (PLUGIN)
« Reply #1 on: 12 Feb 2019, 21:21 »
What version of AGS are you using? Drawing to VirtualScreen did not work for Direct3D and OpenGL before AGS 3.4.1. It was also proven to work somewhat slower for non-software driver in 3.4.1 and later (depending on game resolution), because it's not an optimal way for these renderers.

Secondly, AFAIK you should not call plugin drawing to screen directly from AGS script, but instead connect to AGS drawing hook.

Since your ParticleUpdate function has both update and draw, and if you really must explicitly call update from the script, it should be split into Update/Draw parts. Update may be called from script, but Draw must be connected to the drawing event.

You may refer to snow rain plugin source, for example the one in our repository: https://github.com/adventuregamestudio/ags/blob/master/Plugins/ags_snowrain/ags_snowrain.cpp

Points of interest:

engine->RequestEventHook(AGSE_PREGUIDRAW); // this asks AGS to call you right after room finished drawing but before GUI is drawn

int AGS_EngineOnEvent(int event, int data) // this is the event callback function
« Last Edit: 12 Feb 2019, 21:30 by Crimson Wizard »

Dualnames

  • AGS Baker
  • Pretty Badass
    • Dualnames worked on one or more games that won an AGS Award!
    •  
    • Dualnames worked on one or more games that was nominated for an AGS Award!
Re: Drawing on screen (PLUGIN)
« Reply #2 on: 12 Feb 2019, 21:39 »
You are correct now it's properly hooked, it needed SetVirtualScreen at the end as well. So question

Code: Adventure Game Studio
  1. BITMAP* ParticleGraph = engine->GetSpriteGraphic(pgraph+particles[h].frame);
  2. engine->BlitSpriteTranslucent(px, py, ParticleGraph,tp);
  3. //drawt.DrawImage(px, py, pgraph+particles[h].frame, tp, pwidth, pheight);
  4.  

This part i want it to scale the sprite to width PWIDTH and height PHEIGHT, before blitspriting it onto the screen, what commands are there for that?

Edit:
Code: Adventure Game Studio
  1. BITMAP* ParticleGraph = engine->GetSpriteGraphic(pgraph+particles[h].frame);
  2. int32 w, h, d;
  3. engine->GetBitmapDimensions(Particle_B, &w, &h, &d);
  4. w=pwidth;
  5.  h=pheight;
  6. engine->ReleaseBitmapSurface(Particle_B);
  7. engine->BlitSpriteTranslucent(px, py, ParticleGraph,tp);
  8.  

Is that the right way?
« Last Edit: 12 Feb 2019, 22:01 by Dualnames »
No more military army stuff. I'm alive and back.

Dualnames

  • AGS Baker
  • Pretty Badass
    • Dualnames worked on one or more games that won an AGS Award!
    •  
    • Dualnames worked on one or more games that was nominated for an AGS Award!
Re: Drawing on screen (PLUGIN)
« Reply #3 on: 12 Feb 2019, 22:18 »
I'm also looking for a command that clears the virtual screen, so that i can use that before accessing it.
No more military army stuff. I'm alive and back.

Re: Drawing on screen (PLUGIN)
« Reply #4 on: 12 Feb 2019, 22:22 »
it needed SetVirtualScreen at the end as well.

Could you explain what the plugin is doing in a nutshell?

SetVirtualScreen only really works in Software mode. It replaces the drawing surface for all the following drawing in the engine. Direct3D and OpenGL drivers will never be able to use it since they don't draw to screen bitmap.

Normally plugins that want to draw something on screen call GetVirtualScreen instead to ask engine for a current stage surface (there are several stages, one for room, another for GUI and so on) and draw your own image to that. Then it will be inserted on AGS screen in between the stages (e.g. between room and GUI).

But if you want to read from what's already drawn on screen, this will generally work only in software mode. I cannot think of an easy way to make it work for hardware-accelerated renderers. Normally they should use shaders.


I'm also looking for a command that clears the virtual screen, so that i can use that before accessing it.

I don't remember if there's plugin function for that, but you may call GetRawBitmapSurface to get bitmap's data pointer and fill its contents with zeroes.
« Last Edit: 12 Feb 2019, 22:28 by Crimson Wizard »

Dualnames

  • AGS Baker
  • Pretty Badass
    • Dualnames worked on one or more games that won an AGS Award!
    •  
    • Dualnames worked on one or more games that was nominated for an AGS Award!
Re: Drawing on screen (PLUGIN)
« Reply #5 on: 12 Feb 2019, 22:27 »
The plugin is drawing particles on the screen. It's a wind effect.

What it does is it draws sprites on the screen, altering their size, their position and their transparency.
In the equivalent of the AGS script, every x loops a sprite is created, then parsing through all the existing particles (flagged with ACTIVE) it moves them based on a force (X and Y) and adjusts their size and transparency.
Then clears the screen and on the next loop it repeats the same processt.

No more military army stuff. I'm alive and back.

Re: Drawing on screen (PLUGIN)
« Reply #6 on: 12 Feb 2019, 22:31 »
The plugin is drawing particles on the screen. It's a wind effect.

What it does is it draws sprites on the screen, altering their size, their position and their transparency.
In the equivalent of the AGS script, every x loops a sprite is created, then parsing through all the existing particles (flagged with ACTIVE) it moves them based on a force (X and Y) and adjusts their size and transparency.
Then clears the screen on the next loop, and redoes that.

Oh, so, you need to call GetVirtualScreen at the beginning of your drawing function. On software mode it will already contain everything drawn before that (like, the room and objects), but in D3D/OGL it will be a clean bitmap filled with transparent pixels (iirc).
Also for compatibility, call GetBitmapDimensions to know the actual size of the virtual screen's bitmap, because it may not be equal to game screen size.

You may then call BlitSpriteTranslucent which does suitable drawing depending on the render mode (software/hardware) internally.

You did not answer about version of AGS, so I have to restate that this refers to AGS 3.4.1 (in earlier versions only software mode will work correctly).
« Last Edit: 12 Feb 2019, 22:33 by Crimson Wizard »

Dualnames

  • AGS Baker
  • Pretty Badass
    • Dualnames worked on one or more games that won an AGS Award!
    •  
    • Dualnames worked on one or more games that was nominated for an AGS Award!
Re: Drawing on screen (PLUGIN)
« Reply #7 on: 12 Feb 2019, 22:43 »
Yes, it's 3.4.1!
No more military army stuff. I'm alive and back.

Dualnames

  • AGS Baker
  • Pretty Badass
    • Dualnames worked on one or more games that won an AGS Award!
    •  
    • Dualnames worked on one or more games that was nominated for an AGS Award!
Re: Drawing on screen (PLUGIN)
« Reply #8 on: 12 Feb 2019, 22:49 »
Mhh, i seemed to be unable to draw on a clean slate, like I want, I'm gonna try some stuff.
No more military army stuff. I'm alive and back.

Re: Drawing on screen (PLUGIN)
« Reply #9 on: 12 Feb 2019, 22:50 »
Oh sorry, I made a mistake. You do not have to call GetVirtualScreen at all if you are using BlitSpriteTranslucent and similar functions, because these draw on virtual screen themselves.
You only need to get virtual screen pointer if you do drawing with your custom functions which edit bitmap data directly.


Mhh, i seemed to be unable to draw on a clean slate, like I want, I'm gonna try some stuff.

What exactly is happening? It's a bit tought to guess the problem.
Also, which renderer are you testing with? Results may differ (in case of mistakes too).
« Last Edit: 12 Feb 2019, 22:53 by Crimson Wizard »

Dualnames

  • AGS Baker
  • Pretty Badass
    • Dualnames worked on one or more games that won an AGS Award!
    •  
    • Dualnames worked on one or more games that was nominated for an AGS Award!
Re: Drawing on screen (PLUGIN)
« Reply #10 on: 12 Feb 2019, 22:54 »
Where it's supposed to draw nothing aka draw fully transparent sprites, instead it's drawing static (non-moving) wind sprites.
Which makes me thing it's not pulling from an empty screen, but rather the version of the screen, one loop before.

I am using D3d9
No more military army stuff. I'm alive and back.

Dualnames

  • AGS Baker
  • Pretty Badass
    • Dualnames worked on one or more games that won an AGS Award!
    •  
    • Dualnames worked on one or more games that was nominated for an AGS Award!
Re: Drawing on screen (PLUGIN)
« Reply #11 on: 12 Feb 2019, 23:14 »
I've tried this as a means of clearing the virtual screen, but nope.
Code: Adventure Game Studio
  1. else if (event == AGSE_POSTSCREENDRAW)
  2.   {
  3.           BITMAP* P = engine->GetVirtualScreen();
  4.           unsigned int32 **spriteMemRef = (unsigned int32 **)engine->GetRawBitmapSurface (P);
  5.           int x,y;
  6.           for (y = 0; y < screen_height; y++)
  7.           {
  8.                   for (x = 0; x < screen_width; x++)
  9.                   {
  10.                           spriteMemRef[y][x]=0;
  11.                   }
  12.          }
  13.          engine->ReleaseBitmapSurface(P);
  14.          engine->SetVirtualScreen(P);
  15.   }
  16.  
No more military army stuff. I'm alive and back.

Dualnames

  • AGS Baker
  • Pretty Badass
    • Dualnames worked on one or more games that won an AGS Award!
    •  
    • Dualnames worked on one or more games that was nominated for an AGS Award!
Re: Drawing on screen (PLUGIN)
« Reply #12 on: 12 Feb 2019, 23:24 »
Actually I figured out the slowdown on the modularized version, so i don't need to do this through a plugin!!
No more military army stuff. I'm alive and back.

Re: Drawing on screen (PLUGIN)
« Reply #13 on: 12 Feb 2019, 23:28 »
I've tried this as a means of clearing the virtual screen, but nope.
Code: Adventure Game Studio
  1. else if (event == AGSE_POSTSCREENDRAW)
  2.   {
  3.           BITMAP* P = engine->GetVirtualScreen();
  4.           unsigned int32 **spriteMemRef = (unsigned int32 **)engine->GetRawBitmapSurface (P);
  5.           int x,y;
  6.           for (y = 0; y < screen_height; y++)
  7.           {
  8.                   for (x = 0; x < screen_width; x++)
  9.                   {
  10.                           spriteMemRef[y][x]=0;
  11.                   }
  12.          }
  13.          engine->ReleaseBitmapSurface(P);
  14.          engine->SetVirtualScreen(P);
  15.   }
  16.  

Well, I keep telling that SetVirtualScreen does not work in D3D.
Also, you first GetVirtualScreen and then set it back, that does not make any sense.

Anyway, this code won't work as you think it does, because in every stage the virtual screen may be a different bitmap. So you are not clearing same bitmap you were drawing to.
On D3D the Virtual Screen is cleared automatically each time (at least supposed to).
« Last Edit: 12 Feb 2019, 23:30 by Crimson Wizard »

Dualnames

  • AGS Baker
  • Pretty Badass
    • Dualnames worked on one or more games that won an AGS Award!
    •  
    • Dualnames worked on one or more games that was nominated for an AGS Award!
Re: Drawing on screen (PLUGIN)
« Reply #14 on: 13 Feb 2019, 00:08 »
Yeah, I'm sorry this is kinda new information and I'm bruteforcing it like a chimp :D
No more military army stuff. I'm alive and back.