Spherical forums

Sphere Development => Sphere Support => Script Support => Topic started by: scojin on March 05, 2017, 11:08:55 am

Title: Surface Questions
Post by: scojin on March 05, 2017, 11:08:55 am
Okay, so I'm making a quest-log type menu that is semi-dynamic, meaning they have a set order and are organized by location, but don't appear until activated.
Like so:
Store
A
B
C
House
A
B
C
D
Forest
A
C
D

So basically I have a function that checks, orders, and creates the selections for the menu and then returns the selection order and the selection display in an object. The display is created basically like so:
Code: [Select]

object.image = new Surface(w,h);
//draw header
prim.blit(object.image,x,y,header);
//draw quests
font.drawText(object.image,x,y,whateverquest.title); //draw title
prim.blit(object.image,x,y,whateverquest.status);         //draw icon

//--------------------------------------------

object.selection = selection_array;
object.display = object.image.toImage();

return object


The problem is when I call the menu to be displayed, it only displays the title(from drawText) and not the header or icon(from prim.blit). This is my first go with surfaces, so maybe I'm just not using them right, or maybe I'm missing something?
Thanks in advance.
Title: Re: Surface Questions
Post by: Fat Cerberus on March 05, 2017, 11:11:46 am
Code: (javascript) [Select]

prim.blit(obj.image,x,y,header);


Shouldn't that be object.image?
Title: Re: Surface Questions
Post by: scojin on March 05, 2017, 11:41:59 am
Yep, that was just a typo. Fix'd
My actual code has a bit more to it, so I made a brief example. :P
Title: Re: Surface Questions
Post by: Radnen on March 06, 2017, 01:39:52 am
To draw on surfaces you need to use the surface API:

Code: (javascript) [Select]

object.image.drawText(x, y, text);
object.image.drawImage(x, y, image); // not too sure on this one


But what are you trying to do? Is this for a menu or for an on-screen hud? I've never used surfaces to draw many things on to unless I'm pre-processing images into one image to draw, but rarely do I do that.
Title: Re: Surface Questions
Post by: Fat Cerberus on March 06, 2017, 01:58:19 am

Code: (javascript) [Select]

object.image.drawText(x, y, text);
object.image.drawImage(x, y, image); // not too sure on this one


But what are you trying to do? Is this for a menu or for an on-screen hud? I've never used surfaces to draw many things on to unless I'm pre-processing images into one image to draw, but rarely do I do that.


He's using the Sphere v2 API (note the new Surface(...)).  Surfaces have no built-in primitives in Sphere v2, you're meant to use Galileo (i.e. Shape objects).  See:
https://github.com/fatcerberus/minisphere/blob/v4.5.4/docs/sphere2-api.txt#L913-L938

The prim module included with the engine provides equivalents for most of the classic primitives, but even it uses Galileo under the hood to the actual rendering.  Here's the code if you're curious how that works:
https://github.com/fatcerberus/minisphere/blob/v4.5.4/assets/system/modules/prim.js

The nice thing about Sphere v2 is that screen is just another Surface - so you can draw stuff just as easily to any surface as you can to the screen.  At least, you're supposed to be able to.  scojin's case seems to be broken, and I can't figure out what's wrong based on reading his code.  I'll have to do some testing myself.
Title: Re: Surface Questions
Post by: scojin on March 06, 2017, 05:27:57 pm
Yeah, that's correct. I'm basically piecing together an image from a few smaller images. I am preprocessing it when the menu is first called so it doesn't have to run the code to build the image on each menu update.
I was just puzzled on why the text would appear correctly but not the images.

I was able to test around and recreate the situation. If I create the surface as an image, it displays whatever image was loaded, however if I 'add' an image afterwards, it doesn't. I'm able to have text appear and I can get graphic primitives to display(line,circle,fill,etc.), but images do not.

If it helps, my menu is basically a loop that 'refreshes' after a key is pressed.
Let me know if you need anymore info.
Title: Re: Surface Questions
Post by: Fat Cerberus on March 06, 2017, 06:23:13 pm
I'll look into it, it's possible there's a bug in miniSphere.  What's weird is that you say primitives render fine, but not images.  If you look at the source code of the prim module:
prim.rect(): https://github.com/fatcerberus/minisphere/blob/v4.5.4/assets/system/modules/prim.js#L152-L165
prim.blit(): https://github.com/fatcerberus/minisphere/blob/v4.5.4/assets/system/modules/prim.js#L22-L37

rect and blit basically do the same thing under the hood, the only difference is whether the triangles are textured or not.  So this is quite the mystery.
Title: Re: Surface Questions
Post by: Radnen on March 07, 2017, 12:27:03 am

He's using the Sphere v2 API (note the new Surface(...)).  Surfaces have no built-in primitives in Sphere v2, you're meant to use Galileo (i.e. Shape objects).  See:
https://github.com/fatcerberus/minisphere/blob/v4.5.4/docs/sphere2-api.txt#L913-L938


Oh damn, lol I'm becoming and old fogy in the community. lol
Title: Re: Surface Questions
Post by: Fat Cerberus on March 07, 2017, 12:37:24 am


He's using the Sphere v2 API (note the new Surface(...)).  Surfaces have no built-in primitives in Sphere v2, you're meant to use Galileo (i.e. Shape objects).  See:
https://github.com/fatcerberus/minisphere/blob/v4.5.4/docs/sphere2-api.txt#L913-L938


Oh damn, lol I'm becoming and old fogy in the community. lol


No problem, hehe.  Everything works differently now, which is jarring at first, but being in the process of upgrading Spectacles to take advantage of all the Sphere v2 stuff now, I would say the changes I made are for the better.  I'm not really unhappy with any of them.  Combined with ES6, Sphere v2 really feels like a fully modern development environment now unlike Sphere 1.x which was really showing its age.

@scojin: I can verify your report, and I'm almost certain this is a bug.  I tried the following code:
Code: (javascript) [Select]

const prim = require('prim');
var surf = new Surface(100, 100);
var img = new Texture('images/titleCard.png');
prim.rect(surf, 10, 10, 50, 50, Color.Chartreuse);
prim.blit(surf, 0, 0, img);
var surfImg = surf.toTexture();
while (Sphere.run()) {
prim.blit(screen, 0, 0, surfImg);
screen.flip();
}


The rectangle is rendered, but the image is not.  Now I just have to figure out why.  By the way, Image was renamed to Texture a few versions ago so you should probably upgrade your miniSphere installation if you want your code to keep running ;)

edit: I found the bug.  When drawing to the screen, texture coordinates (U/V) are normalized and go from [0-1] bottom-to-top.  When drawing to a surface, however, they are in pixels and go from [0-w/h).  So what's actually happening is that prim.blit() correctly assumes the normalized coordinates, and only the top-left pixel of the image gets drawn.  I'm not sure what causes that yet, I'll have to study the Galileo code.
Title: Re: Surface Questions
Post by: Fat Cerberus on March 07, 2017, 01:11:45 am
@scojin: Here's a monkey patch you can use until I fix the bug:
Code: (javascript) [Select]

require('prim').blit =
function blit(surface, x, y, image, mask)
{
mask = mask || Color.White;

var x1 = x;
var y1 = y;
var x2 = x1 + image.width;
var y2 = y1 + image.height;
var v1 = surface === screen ? 1 : 0;
var u2 = surface === screen ? 1 : image.width;
var v2 = surface === screen ? 0 : image.height;
var shape = new Shape([
{ x: x1, y: y1, u: 0,  v: v1, color: mask },
{ x: x2, y: y1, u: u2, v: v1, color: mask },
{ x: x1, y: y2, u: 0,  v: v2, color: mask },
{ x: x2, y: y2, u: u2, v: v2, color: mask },
], image, ShapeType.TriStrip);
shape.draw(surface);
}


The above patch won't work after the bug is fixed, so be sure to put it in a place you won't forget it exists.  Otherwise down the road you might wonder why your game suddenly broke after an update :P
Title: Re: Surface Questions
Post by: scojin on March 07, 2017, 05:01:37 pm
Thanks, Cerberus! Major kudos!
Works like a charm.
Title: Re: Surface Questions
Post by: Fat Cerberus on March 10, 2017, 01:44:42 am
@scojin: I found the cause of the bug; it'll be fixed in miniSphere 4.5.5.  Allegro tracks shaders per render target.  When drawing Shapes to a surface, miniSphere was incorrectly applying the shader before switching the render target, meaning the shader got applied to the screen while the surface actually being drawn still used the Allegro default shader--which maps U/V to image pixels and thus causing prim.blit() to fail.  Very simple to fix. :)

edit: aaaaand miniSphere 4.5.5 is out now.
Title: Re: Surface Questions
Post by: scojin on March 10, 2017, 10:49:25 pm
Magnifico!