In my game I have a small viewport that has a live render of the game the problem I seem to have is that I cannot resize the texture to fix into the viewport, I've achieved the task before with this but it seems to not work like this.
->GetLevelDesc(0, &desc);
D3DXVECTOR2 scale = D3DXVECTOR2(desc.Width, desc.Height);
D3DXMatrixTransformation2D(&matrix, NULL, 0, &scale, NULL, 0, NULL);
->SetTransform(D3DTS_TEXTURE0, &matrix);
Also if I transform a sprite with the scale vector, it becomes 100 % scaled to screen, which is odd because desc.Width and desc.Height are 243, this is also being rendered to a "render target" that texture is a smaller resolution.
Related
So, I'm making a 2D game and I have some textures. I will like some of them to drop a shadow, there is something like drop-shadow in css for SDL2?
Render the texture first, then render a slightly larger semi-transparent gray square slightly behind it. If you want rounded corners, use a shader that increases alpha as you get further from the corners.
Since noone mentionned it yet, here it is:
int SDL_SetTextureColorMod(SDL_Texture* texture,
Uint8 r,
Uint8 g,
Uint8 b)
https://wiki.libsdl.org/SDL_SetTextureColorMod
This function multiplies a texture color channels when copying it to the SDL_Renderer*. Using it with 0 as r, g and b arguments would make your texture pitch black but not affect the alpha, so the texture would keep its shape (like in the case of a transparent PNG). You just have to copy that shadow before (= behind) your texture, with a slight offset. You can also change the overall transparency of the shadow, with SDL_SetTextureAlphaMod(SDL_Texture* texture, Uint8 a)
Just don't forget to set the values back to 255 when you're done.
Code example:
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
SDL_RenderClear(renderer);
// [...] draw background, etc... here
SDL_Rect characterRect;
// [...] fill the rect however you want
SDL_Rect shadowRect(characterRect);
shadowRect.x += 30; // offsets the shadow
shadowRect.y += 30;
SDL_SetTextureColorMod(characterTexture, 0, 0, 0); // makes the texture black
SDL_SetTextureAlphaMod(characterTexture, 191); // makes the texture 3/4 of it's original opacity
SDL_RenderCopy(renderer, characterTexture, NULL, &shadowRect); // draws the shadow
SDL_SetTextureColorMod(characterTexture, 255, 255, 255); // sets the values back to normal
SDL_SetTextureAlphaMod(characterTexture, 255);
SDL_RenderCopy(renderer, characterTexture, NULL, &characterRect); // draws the character
// [...] draw UI, additionnal elements, etc... here
SDL_RenderPresent(renderer);
I am using a FrameBuffer to rasterize several TextureRegions in a single TextureRegion, to be drawn on an Image/Actor afterwards.
The constructor of a FrameBuffer is the following:
FrameBuffer(Pixmap.Format format, int width, int height, boolean hasDepth)
I found that if I put Gdx.graphics.getWidth()/getHeight() as the width and height parameters in the constructor the image is drawn correctly, but if I put something else (like the rasterized texture size) the texture is way smaller and is pixelated if I increase the size. Have I missed something ?
TextureRegion initialTexture = getTexture();
// And other textures, which are not shown here for better readability
FrameBuffer frameBuffer = new FrameBuffer(Pixmap.Format.RGBA8888, (int)initialTexture.getRegionWidth(), (int)initialTexture.getRegionHeight(), false);
Batch batch = new SpriteBatch();
// Adding these lines did the trick
Camera camera = new OrthographicCamera(frameBuffer.getWidth(), frameBuffer.getHeight());
camera.position.set(frameBuffer.getWidth() / 2, frameBuffer.getHeight() / 2, 0);
camera.update();
batch.setProjectionMatrix(camera.combined);
frameBuffer.begin();
batch.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, 1, 1, 0);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
batch.begin();
batch.setColor(TAPColor.TAP_WHITE);
batch.draw(initialTexture, 0, 0);
// Also draw other textures
batch.end();
frameBuffer.end();
TextureRegion finalTexture = new TextureRegion(frameBuffer.getColorBufferTexture());
Image image = new Image(finalTexture);
image.setSize(finalTexture.getRegionWidth(), finalTexture.getRegionHeight());
image.setPosition(0, 0);
addActor(image);
I had some problems too, one thing that made it simple was:
Matrix4 projection = new Matrix4();
projection.setToOrtho2D(0, 0, 32, 48);
batch.setProjectionMatrix(projection);
When I do this:
SpriteBatch spriteBatch = new SpriteBatch();
spriteBatch.setProjectionMatrix(new Matrix4().setToOrtho(0, 320, 0, 240, -1, 1));
spriteBatch.begin();
spriteBatch.draw(textureRegion, 0, 0);
spriteBatch.end();
SpriteBatch will draw the textureRegion onto the coordinate system 320-240 that I have specified to the whole screen. Say I want to draw with the same coordinate system 320 240 but only on the left half of the screen (which means everything will be scaled down horizontally in the left side, leaving the right half of the screen black), how can I do?
You're going to want to use the ScissorStack. Effectively, you define a rectangle that you want to draw in. All drawing will be in the rectangle that you defined.
Rectangle scissors = new Rectangle();
Rectangle clipBounds = new Rectangle(x,y,w,h);
ScissorStack.calculateScissors(camera, spriteBatch.getTransformMatrix(), clipBounds, scissors);
ScissorStack.pushScissors(scissors);
spriteBatch.draw(...);
spriteBatch.flush();
ScissorStack.popScissors();
This will limit rendering to within the bounds of the rectangle "clipBounds".
It is also possible push multiple rectangles. Only the pixels of the sprites that are within all of the rectangles will be rendered.
From http://code.google.com/p/libgdx/wiki/GraphicsScissors
Before rendering the batch, you can set the viewport to draw on a specific screen area. The important line is:
Gdx.gl.glViewport(x, y, w, h);
The viewport usually starts at x = 0 and y = 0 and extends to the full width and height of the screen. If we want to see only a part of that original viewport, we need to change both the size and the starting position. To draw only on the left half of the screen, use:
x = 0;
y = 0;
w = Gdx.graphics.getWidth()/2;
h = Gdx.graphics.getWidth();
I found the solution here and originally answered this question to a slightly more complicated problem, but the technique is the same.
To focus on any different portion of the viewport, simply choose x, y, w, and h accordingly. If you're going to do any more rendering in the normal fashion, make sure to reset the viewport with the original x, y, w, and h values.
Perhaps I am misunderstanding the question, but could you not just double the viewport width, setting it to 640 instead of 320?
SpriteBatch spriteBatch = new SpriteBatch;
spriteBatch.setProjectionMatrix(new Matrix4().setToOrtho(0, 640, 0, 240, -1, 1));
spriteBatch.begin();
spriteBatch.draw(textureRegion, 0, 0);
spriteBatch.end();
You could either
double the viewport width of the SpriteBatch
use a Sprite and set its width scale to 0.5f (be careful about the origin) and use its draw(SpriteBatch) method to draw it.
I'm working on a game using DirectX 9. Here's what I'm trying to do:
After the scene is rendered, on top of it I want to render few sprites: a black cover on entire scene and a few sprites, which are masks showing where the cover should have holes. So far I tried messing with blend mode but with no luck. My code setting it up looks like this:
D3DD->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
D3DD->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
D3DD->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
I guess the best way would be to multiply each sprites alpha, but according to http://msdn.microsoft.com/en-us/library/windows/desktop/bb172508%28v=vs.85%29.aspx no such mode is supported. Is There another way to do this?
edit
Following Nico Schertler's answer, here's the code I came up with:
LPDIRECT3DTEXTURE9 pRenderTexture;
LPDIRECT3DSURFACE9 pRenderSurface,
pBackBuffer;
// create texture
D3DD->CreateTexture(1024,
1024,
1,
D3DUSAGE_RENDERTARGET,
D3DFMT_R5G6B5,
D3DPOOL_DEFAULT,
&pRenderTexture,
NULL);
pRenderTexture->GetSurfaceLevel(0,&pRenderSurface);
// store old render target - back buffer
D3DD->GetRenderTarget(0,&pBackBuffer);
// set new render target - texture
D3DD->SetRenderTarget(0,pRenderSurface);
//clear texture to opaque black
D3DD->Clear(0,
NULL,
D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER,
D3DCOLOR_XRGB(0,0,0),
32.0f,
0);
// set blending
D3DD->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ZERO);
D3DD->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_ONE);
D3DD->SetRenderState(D3DRS_SRCBLENDALPHA, D3DBLEND_ZERO);
D3DD->SetRenderState(D3DRS_DESTBLENDALPHA, D3DBLEND_SRCALPHA);
D3DD->SetRenderState(D3DRS_SEPARATEALPHABLENDENABLE, TRUE);
//// now I render hole sprites the usual way
// restore back buffe as render target
D3DD->SetRenderTarget(0,pBackBuffer);
// restore blending
D3DD->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
D3DD->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
D3DD->SetRenderState(D3DRS_SRCBLENDALPHA, D3DBLEND_SRCALPHA);
D3DD->SetRenderState(D3DRS_DESTBLENDALPHA, D3DBLEND_INVSRCALPHA);
D3DD->SetRenderState(D3DRS_SEPARATEALPHABLENDENABLE, FALSE);
ulong color = ulong(-1);
Vertex2D v[4];
v[0] = Vertex2D(0, 0, 0);
v[1] = Vertex2D(1023, 0, 0);
v[3] = Vertex2D(1023, 1023, 0);
v[2] = Vertex2D(0, 1023, 0);
D3DD->SetTexture(0, pRenderTexture);
D3DD->SetFVF(D3DFVF_XYZRHW | D3DFVF_DIFFUSE | D3DFVF_TEX1);
D3DD->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, v, sizeof(Vertex2D));
D3DD->SetTexture(0, NULL);
// release used resources
pRenderTexture->Release();
pRenderSurface->Release();
pBackBuffer->Release();
Unfortunatelly, the app crashes when restoring the old render target. Any advice?
Firstly, you should create the mask in a separate texture first. Then you can add the holes as needed. Finally, draw the mask on the screen:
Initialize the texture
Clear it to opaque black
Using the following blend states:
D3DRS_SRCBLEND -> D3DBLEND_ZERO (hole's color does not matter)
D3DRS_DESTBLEND -> D3DBLEND_ONE (preserve the black color)
D3DRS_SRCBLENDALPHA -> D3DBLEND_ZERO
D3DRS_DESTBLENDALPHA -> D3DBLEND_SRCALPHA
D3DRS_SEPARATEALPHABLENDENABLE -> TRUE
Draw each hole sprite
Restore default blending (src_alpha / inv_src_alpha)
Render the texture as a sprite to the back buffer
The above blend state assumes that the holes are opaque where there should be a hole. Then, the color is calculated by:
blended color = 0 * hole sprite color + 1 * background color
which should always be black.
And the alpha channel is calculated by:
blended alpha = 0 * hole sprite alpha + (1 - hole sprite alpha) * background alpha
So where the hole sprite is opaque, the blended alpha becomes 0. Where it is transparent, the blended alpha is the previous value. Values in between are blended.
I just started to make another small game in SDL, i made my 2 players - represented by the top half of a circle. So far, i draw a background, and the two players on top.
if (SDL_Init(SDL_INIT_VIDEO) < 0 ) return 1;
if (!(screen = SDL_SetVideoMode(WIDTH, HEIGHT, DEPTH,SDL_HWSURFACE| SDL_DOUBLEBUF)))
{
SDL_Quit();
return 1;
}
SDL_Surface* surface2 = SDL_CreateRGBSurface(SDL_HWSURFACE, WIDTH, HEIGHT, 32,
rmask, gmask, bmask, amask);
SDL_FillRect(surface2, 0, SDL_MapRGBA(surface2->format,0,0xAA,0,0xFF));
//in the while loop
SDL_BlitSurface(surface2,0,screen,0);
When i move the player, it moves 10px per movement. I have implemented smooth movement, with timers, so that is not the case. The intersting part is, that when i choose to leave the surface2 black - without a fillrect at the start, then everything works smooth.
I now fill the screen surface with a color, and it also runs smoothely. So what might be the problem?