I am trying to get the Texture from Sprite or Atlas Region created by Texture Atlas.
atlas=new TextureAtlas(Gdx.files.internal("Test.pack"));
region=atlas.findRegion("green");
or
Sprite s = atlas.createSprite("red");
texture = s.getTexture();
I have given the name of image in findRegion and createSprite method, it always picks the other image object. I want to get the texture of the image so that part of that texture can be rendered.
Here is the Packer image:
http://i61.tinypic.com/neupo2.png
Even if i try to get green region or red, it always returns blue. Any help would be appreciated.
When you do "textureAtlas.findRegion("objectTexture").getTexture();" (from James Skemp's answer) you're getting the whole texture from the atlas, not just from the region "objectTexture".
Don't bother creating Texture to create the Sprite, you can use the TextureRegion to create the Sprite. Something like this:
atlas=new TextureAtlas(Gdx.files.internal("Test.pack"));
regionGreen=atlas.findRegion("green");
Sprite s = new Sprite(regionGreen);
My use case is slightly different, but I was running into the same issue.
I have an object, which extends Actor, that I want to draw using a region in an atlas.
public class MyObject extends Actor {
private Texture texture;
public MyObject() {
TextureAtlas textureAtlas = new TextureAtlas(Gdx.files.internal("xxx.atlas"));
texture = textureAtlas.findRegion("objectTexture").getTexture();
Gdx.app.log(TAG, "Texture width: " + texture.getWidth());
Gdx.app.log(TAG, "Texture height: " + texture.getHeight());
setBounds(getX(), getY(), Constants.STANDARD_TILE_WIDTH, Constants.STANDARD_TILE_HEIGHT);
// ...
}
#Override
public void draw(Batch batch, float parentAlpha) {
batch.draw(texture,
worldPosition.x * Constants.STANDARD_TILE_WIDTH, worldPosition.y * Constants.STANDARD_TILE_WIDTH,
texture.getWidth(), texture.getHeight());
}
}
Instead of just the region I was expecting I instead received the entire atlas, so my logged texture width and height were 1024 x 128.
Unfortunate, and still not sure why getTexture() returns too much, but switching over to batchDraw(TextureRegion, ...) at least got me in a better place.
public class MyObject extends Actor {
private TextureRegion texture;
public MyObject() {
TextureAtlas textureAtlas = new TextureAtlas(Gdx.files.internal("xxx.atlas"));
texture = textureAtlas.findRegion("objectTexture");
setBounds(getX(), getY(), Constants.STANDARD_TILE_WIDTH, Constants.STANDARD_TILE_HEIGHT);
// ...
}
#Override
public void draw(Batch batch, float parentAlpha) {
batch.draw(texture, getX(), getY());
}
}
Based upon what I saw with my sprites, the questioner was seeing a blue square for the same reason I was; the entire image is getting loaded by getTexture() and since it starts at the bottom left, you're always seeing a blue square.
Using the Sprite(TextureRegion) constructor may have also resolved their issue.
Seems to me your problem is the Test.pack file, not the texture.
It works with this one I packed with GDX Texture Packer:
Test.png
format: RGBA8888
filter: Nearest,Nearest
repeat: none
blue
rotate: false
xy: 1, 1
size: 51, 51
orig: 51, 51
offset: 0, 0
index: -1
green
rotate: false
xy: 54, 1
size: 51, 51
orig: 51, 51
offset: 0, 0
index: -1
red
rotate: false
xy: 107, 1
size: 51, 51
orig: 51, 51
offset: 0, 0
index: -1
yellow
rotate: false
xy: 160, 1
size: 51, 51
orig: 51, 51
offset: 0, 0
index: -1
Use index also to get it.Get the index from pack file or .atlas file.
atlas=new TextureAtlas(Gdx.files.internal("Test.pack"));
region=atlas.findRegion("green",index);
or
Sprite s = atlas.createSprite("red",index);
texture = s.getTexture();
Related
I have a big problem with frame rate. When I draw only 1 sprite and try to move it when FPS is below 400 without VSync I have lags. It isn't smooth movement. When I use VSync it works almost good, but every second instead 60 fps, frame rate jump to ~2000 for 1 frame. When this happen movement stutters. Also without this frame rate jumps, movement stutters, but less than without VSync. When FPS > 500 everything is fine. This isn't due to bad hardware. Can I do something with it?
#Override
public void create () {
batch = new SpriteBatch();
img = new Texture("badlogic.jpg");
img.setFilter(TextureFilter.Nearest, TextureFilter.Nearest);
font = new BitmapFont();
player = new Sprite(img);
x = 100;
y=100;
player.setPosition(x, y);
//camera = new OrthographicCamera(640, 480);
//multiGame = new MultiGame();
//multiGame.create();
//camera.position.set(camera.viewportWidth / 2f, camera.viewportHeight / 2f, 0);
//camera.update();
}
#Override
public void render ()
{
Gdx.gl.glClearColor(1, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
update();
batch.begin();
font.draw(batch, "" + (int)(1/time), 600, 450);
player.draw(batch);
batch.end();
}
private void update()
{
time = Gdx.graphics.getDeltaTime();
if(Gdx.input.isKeyPressed(Keys.D))
{
x+=100 * time;
}
if(Gdx.input.isKeyPressed(Keys.D))
{
x-=60 * time;
}
player.setPosition(x, y);
}
}
Only generated code with some lines of keys handling and sprite drawing. Every second FPS grow up to 2000 for 1 frame... and sprite is stuttering.
It's desktop launcher:
public static void main (String[] arg) {
LwjglApplicationConfiguration config = new LwjglApplicationConfiguration();
config.vSyncEnabled = true;
config.foregroundFPS=60;
config.backgroundFPS=60;
new LwjglApplication(new IndustrialServer(), config);}
EDIT:
I discovered that when it's in window mode... it stuttered... many times in 1 second... but when it's in fullscreen mode only every second... (it's connected with fps jumping because when application work in window mode... it stuttered without jump FPS... :/ )
And i rejestred this fps when app worked for 30 seconds (FPS < 40 or > 70):
742,
104,
19,
1749,
39,
132,
76,
76,
77,
26,
878,
84,
39,
118,
89,
91,
112,
105,
39,
133,
37,
149,
37,
159,
33,
331,
37,
148,
35,
195,
36,
185,
2,
3,
2848,
74,
74
I also discovered that every action in system, change of process and change of procesor frequency (because it oscillate between 2000MHz and 3200 MHZ) generate FPS jump (between 3 to 12000!!!)
And... when i set max FPS to 59 or smaller... it not stutter but... you can see typical for vsync when it's off video artifacts.
Any video card settings don't help. Any "adaptive vsync" or something... The problem is also when i delete everything from my code and only black screen is set...
I really don't want to use full power of CPU and GPU all the time when someone play game... Especially if this person play on laptop.
Im try to get a super simple lwjgl app going that draws a simple triangle, but cant find the right order of calls to make anything meaningful appear. im using a simple vertex buffer and no shaders.
for some reason each frame is a white triangle on the lower right side of the frame, regardless of what is in the actual vertex buffer.
public void run() {
GLFWErrorCallback.createThrow().set();
glfwInit();
glfwDefaultWindowHints();
glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE);
glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE);
long h_window = glfwCreateWindow(640, 480, "test", 0, 0);
glfwShowWindow(h_window);
glfwMakeContextCurrent(h_window);
GL.createCapabilities();
glEnableClientState(GL_VERTEX_ARRAY);
int b_vertex = glGenBuffers();
float[] vertex = {
0,0,0,
0,0,0,
0,0,0
};
glBindBuffer(GL_ARRAY_BUFFER, b_vertex);
glBufferData(GL_ARRAY_BUFFER, vertex, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
while (!glfwWindowShouldClose(h_window)) {
glClearColor(0, 0, 0, 0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, b_vertex);
glVertexAttribPointer(0, 3, GL_FLOAT, false, 0, 0L);
glDrawArrays(GL_TRIANGLES, 0, 3);
glDisableVertexAttribArray(0);
glfwSwapBuffers(h_window);
glfwWaitEventsTimeout(1f / 30f);
}
}
im definitely missing something, but have no idea what it is. here is what this shows:
Screenshot of Running app
Found the problem.
glVertexPointer(3, GL_FLOAT, 0, 0L);
is for shaderless buffer descriptions
glVertexAttribPointer(0, 3, GL_FLOAT, false, 0, 0L);
is for buffer descriptions that also bind buffers to shader inputs
I use RenderTexture to render a layer with all its nodes to a texture then apply an OpenGL shader on that texture to create post-process effects. It works all fine except with Sprite3D and Billboard nodes. It has been asked on their forums a few times without any response. I wonder if anyone got this to work.
Here is an example:
Layer* gameLayer = Layer::create();
this->addChild(gameLayer, 0);
auto dir = Director::getInstance()->getWinSize();
Camera *camera = Camera::createPerspective(60, (GLfloat)dir.width / dir.height, 1, 1000);
camera->setPosition3D(Vec3(0, 100, 100));
camera->lookAt(Vec3(0, 0, 0), Vec3(0, 1, 0));
gameLayer->addChild(camera); //add camera to the scene
// You'll get a NULL camera inside BillBoard::calculateBillbaordTransform() function
// if you call visit()
/*auto billboard = BillBoard::create("cocos2d-x.png", BillBoard::Mode::VIEW_POINT_ORIENTED);
billboard->setPosition(Vec2(VisibleRect::center().x, VisibleRect::center().y));
gameLayer->addChild(billboard, 100);*/
// This one won't render into the texture
Sprite3D* sprite3D = Sprite3D::create("blend_test/character_3_animations_test.c3b");
sprite3D->setScale(5.0f); //sets the object scale in float
sprite3D->setRotation3D(Vec3(0.0f, 0.0f, 0.0f));
//sprite3D->setPosition3D(Vec3(VisibleRect::center().x, VisibleRect::center().y, 0.0f)); //sets sprite position
sprite3D->setPosition(Vec2(VisibleRect::center().x, VisibleRect::center().y));
gameLayer->addChild(sprite3D, 1); //adds sprite to scene, z-index: 1
// This one works just fine and appears black and white as expected
// in the resulting texture
Sprite* sprite2D = Sprite::create("cocos2d-x.png");
sprite2D->setPosition(Vec2(VisibleRect::center().x, VisibleRect::center().y));
gameLayer->addChild(sprite2D);
// Black and white OpenGL shader
GLProgram* glProgram = GLProgram::createWithFilenames("shaders/gray.vert", "shaders/gray.frag");
glProgram->bindAttribLocation(GLProgram::ATTRIBUTE_NAME_COLOR, GLProgram::VERTEX_ATTRIB_POSITION);
glProgram->bindAttribLocation(GLProgram::ATTRIBUTE_NAME_POSITION, GLProgram::VERTEX_ATTRIB_COLOR);
glProgram->bindAttribLocation(GLProgram::ATTRIBUTE_NAME_TEX_COORD, GLProgram::VERTEX_ATTRIB_TEX_COORD);
glProgram->bindAttribLocation(GLProgram::ATTRIBUTE_NAME_TEX_COORD1, GLProgram::VERTEX_ATTRIB_TEX_COORD1);
glProgram->bindAttribLocation(GLProgram::ATTRIBUTE_NAME_TEX_COORD2, GLProgram::VERTEX_ATTRIB_TEX_COORD2);
glProgram->bindAttribLocation(GLProgram::ATTRIBUTE_NAME_TEX_COORD3, GLProgram::VERTEX_ATTRIB_TEX_COORD3);
glProgram->bindAttribLocation(GLProgram::ATTRIBUTE_NAME_NORMAL, GLProgram::VERTEX_ATTRIB_NORMAL);
glProgram->bindAttribLocation(GLProgram::ATTRIBUTE_NAME_BLEND_WEIGHT, GLProgram::VERTEX_ATTRIB_BLEND_WEIGHT);
glProgram->bindAttribLocation(GLProgram::ATTRIBUTE_NAME_BLEND_INDEX, GLProgram::VERTEX_ATTRIB_BLEND_INDEX);
glProgram->link();
glProgram->updateUniforms();
RenderTexture* renderTexture = RenderTexture::create(VisibleRect::width(), VisibleRect::height());
renderTexture->retain();
Sprite* ppSprite = Sprite::createWithTexture(renderTexture->getSprite()->getTexture());
ppSprite->setTextureRect(Rect(0, 0, ppSprite->getTexture()->getContentSize().width,
ppSprite->getTexture()->getContentSize().height));
ppSprite->setAnchorPoint(Point::ZERO);
ppSprite->setPosition(Point::ZERO);
ppSprite->setFlippedY(true);
ppSprite->setGLProgram(glProgram);
this->addChild(ppSprite, 100);
renderTexture->beginWithClear(0.0f, 0.0f, 0.0f, 0.0f);
auto renderer = _director->getRenderer();
auto& parentTransform = _director->getMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW);
gameLayer->visit(renderer, parentTransform, true);
//gameLayer->visit();
renderTexture->end();
ppSprite->setTexture(renderTexture->getSprite()->getTexture());
Cocos2d-x v3.11.1 (current as of this post) and below don't properly support RenderTextures with Sprite3D because of a clear depth buffer bug.
There is a GitHub issue on the bug. But a workaround now exists:
...
sprite3D->setForce2DQueue(true); // puts your Sprite3D on same render queue as the RenderTexture. More info below.
...
auto rt = RenderTexture::create(1280, 720, Texture2D::PixelFormat::RGBA8888, GL_DEPTH24_STENCIL8); // By default a depth buffer isn't created
rt->setKeepMatrix(true); // required
...
...
rt->beginWithClear(0, 0, 0, 0, 1); // required, clears the depth buffer
Also, changes need to be made to RenderTexture.cpp. This fixes the clear depth buffer bug in Cocos2d-x.
void RenderTexture::onClear()
{
// save clear color
GLfloat oldClearColor[4] = {0.0f};
GLfloat oldDepthClearValue = 0.0f;
GLint oldStencilClearValue = 0;
GLboolean oldDepthWrite = GL_FALSE;
// backup and set
if (_clearFlags & GL_COLOR_BUFFER_BIT)
{
glGetFloatv(GL_COLOR_CLEAR_VALUE, oldClearColor);
glClearColor(_clearColor.r, _clearColor.g, _clearColor.b, _clearColor.a);
}
if (_clearFlags & GL_DEPTH_BUFFER_BIT)
{
glGetFloatv(GL_DEPTH_CLEAR_VALUE, &oldDepthClearValue);
glClearDepth(_clearDepth);
glGetBooleanv(GL_DEPTH_WRITEMASK, &oldDepthWrite);
glDepthMask(true);
}
if (_clearFlags & GL_STENCIL_BUFFER_BIT)
{
glGetIntegerv(GL_STENCIL_CLEAR_VALUE, &oldStencilClearValue);
glClearStencil(_clearStencil);
}
// clear
glClear(_clearFlags);
// restore
if (_clearFlags & GL_COLOR_BUFFER_BIT)
{
glClearColor(oldClearColor[0], oldClearColor[1], oldClearColor[2], oldClearColor[3]);
}
if (_clearFlags & GL_DEPTH_BUFFER_BIT)
{
glClearDepth(oldDepthClearValue);
glDepthMask(oldDepthWrite);
}
if (_clearFlags & GL_STENCIL_BUFFER_BIT)
{
glClearStencil(oldStencilClearValue);
}
}
See the issue for more details. I also made an example gist of the workaround. Screenshot below.
I'm not sure about billboards, but this workaround might fix it too.
Info on Cocos2d-x render queues:
The Sprite3D needs to be on the same render queue as the RenderTexture. Cocos2d-x (as of v3.7 or so) now has 5 render queues:
Global Z Order < 0
3D Opaque
3D Transparent
Global Z Order == 0 (default for 2D)
Global Z Order > 0
You can put the Sprite3D and the RenderTexture on the last queue with setGlobalZOrder(1) or just put the Sprite3D in the 2D queue with sprite3D->setForce2DQueue(true).
unlike cocos2d RenderTexture the following worked fine for 3D screen capture (or anything i imagine)!
Sprite * CcGlobal::getScreenAsSprite(void) {
Size screenSize = Director::getInstance()->getWinSize();
int width = screenSize.width;
int height = screenSize.height;
std::shared_ptr<GLubyte> buffer(new GLubyte[width * height * 4], [](GLubyte* p) { CC_SAFE_DELETE_ARRAY(p); });
glPixelStorei(GL_PACK_ALIGNMENT, 1);
glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, buffer.get());
Image* image = new (std::nothrow) Image;
image->initWithRawData(buffer.get(), width * height * 4, width, height, 8);
Texture2D *texture = new (std::nothrow) Texture2D();
texture->initWithImage(image);
SpriteFrame *spriteFrame = SpriteFrame::createWithTexture(texture, Rect(Vec2(0, 0), screenSize));
Sprite *sprite = Sprite::createWithSpriteFrame(spriteFrame);
sprite->setFlippedY(true);
delete image;
return sprite;
}
===================================================
In a Libgdx 1.x Stage, my goal is to apply a dark semi transparent mask on my screen except an area that should display the original screen.
My global render method:
public void render() {
Gdx.gl.glClearColor(0, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
batch.setShader(null);
update();
stage.act(Gdx.graphics.getDeltaTime());
stage.draw();
batch.begin();
darkener.draw(batch, 0.7f);
spotlight.draw(batch, 1f);
batch.end();
}
Both instances of objects Darkener and Spotlight are Sprites made from a pure white 4x4 texture:
spotlight = new Sprite(new Texture(Gdx.files.internal("data/ui/whitepixel.png")));
darkener = new Sprite(new Texture(Gdx.files.internal("data/ui/whitepixel.png")));
I give my Darkener object the size of the screen, and my Spotlight object the size of the area I want not to be darkened.
Here is the draw method of my object darkener:
public void draw(Batch batch, float alpha) {
darkener.draw(batch, alpha);
}
And the draw method of my Spotlight object:
public void draw(Batch batch, float alpha) {
batch.setBlendFunction(GL20.GL_DST_COLOR, GL20.GL_SRC_ALPHA);
spotlight.draw(batch, alpha);
batch.setBlendFunction(GL20.GL_SRC_ALPHA, GL20.GL_ONE_MINUS_SRC_ALPHA);
}
My problem is about blending:
With the parameters:
darkener.draw(batch, 0.7f);
spotlight.draw(batch, 1f);
The preserved (spotlight) area is darker than the original.
With the parameters:
darkener.draw(batch, 0.3f);
spotlight.draw(batch, 1f);
The preserved (spotlight) area is brighter (saturated) than the original.
With the paremeters:
darkener.draw(batch, 0.5f);
spotlight.draw(batch, 1f);
The preserved (spotlight) area is exactly like the original (so, as I want it). The problem is that I want to be able to set different values for my Darkener either < 0.5f or > 0.5f.
What I am doing wrong?
The blend function you're using for the spotlight takes the current pixel brightness and multiplies it by (1+alpha).
So if you darken to 0.7 of brightness (using a darkener alpha of 0.3), you want the spotlight to multiply the brightness by 1/0.7 = 1.429 so you should use a spotlight alpha of 0.429. So:
spotlightAlpha = 1/(1-darkenerAlpha) - 1; //assuming darkener RGB is black
The problem is if you darken to less than 0.5 brightness (darkner alpha > 0.5), because alpha cannot be greater than 1. You would have to run the spotlight with alpha 1 repeatedly until the brightness is above 0.5 and then one more time with the appropriate value.
You will lose color precision the darker you go so this method may not be suitable. Might want to consider drawing 8 dark boxes instead. And if you want the spotlight to be non-rectangular you can make its sprite inverted to fill in the middle rectangle.
I'm trying to make a game where you build a spaceship from parts, and fly it around and such.
I would like to create the ship from a series of components (from a TextureAtlas for instance). I'd like to draw the ship from it's component textures, and then save the drawn ship as one large Texture. (So i don't have to draw 50 component textures, just one ship texture. What would be the best way to go about this?
I've been trying to do so using a FrameBuffer. I've been able to draw the components to a Texture, and draw the texture to the screen, but no matter what I try the Texture ends up with a solid background the size of the frame buffer. It's like the clear command can't clear with transparency. Here's the drawing code I have at the moment. The ship is just a Sprite which i save the FrameBuffer texture to.
public void render(){
if (ship == null){
int screenwidth = Gdx.graphics.getWidth();
int screenheight = Gdx.graphics.getHeight();
SpriteBatch fb = new SpriteBatch();
FrameBuffer fbo = new FrameBuffer(Format.RGB888, screenwidth, screenheight, false);
fbo.begin();
fb.enableBlending();
Gdx.gl.glBlendFuncSeparate(GL20.GL_SRC_ALPHA, GL20.GL_ONE_MINUS_SRC_ALPHA, GL20.GL_ONE, GL20.GL_ONE_MINUS_SRC_ALPHA);
Gdx.gl.glClearColor(1, 0, 1, 0);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
fb.begin();
atlas.createSprite("0").draw(fb);
fb.end();
fbo.end();
ship = new Sprite(fbo.getColorBufferTexture());
ship.setPosition(0, -screenheight);
}
Gdx.gl.glClearColor(1, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
batch.begin();
batch.enableBlending();
batch.setBlendFunction(GL20.GL_ONE, GL20.GL_ZERO);
ship.draw(batch);
batch.end();
}
The problem here lies in this line:
FrameBuffer fbo = new FrameBuffer(Format.RGB888, screenwidth, screenheight, false);
specifically with Format.RGB888. This line is saying that your FrameBuffer should be Red (8 bits) followed by Green (8 bits) followed by Blue (8 bits). Notice however, that this format doesn't have any bits for Alpha (transparency). In order to get transparency out of your frame buffer, you probably instead want to use the Format.RGBA8888, which includes an additional 8 bits for Alpha.
Hope this helps.