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?
Related
This is the code as it is but I'm having trouble making SDL_Rect work or cairo move to / line to. It produces a blank black window. I found out that it is possible for cairo to draw on an SDL2 window but don't know how I would go about making it work. Majority of the code I see uses GTK+.
SDL_Window* mainWindow;
SDL_Renderer* mainRenderer;
SDL_CreateWindowAndRenderer(1280, 960, SDL_WINDOW_SHOWN, &mainWindow, &mainRenderer);
cairo_surface_t* surface;
cairo_t* cr;
surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 1200, 900);
cr = cairo_create(surface);
cairo_set_source_rgb(cr, 0.0, 0.0, 0.0);
cairo_set_line_width(cr, 25);
cairo_set_source_rgb(cr, 1.0, 1.0, 1.0);
cairo_move_to(cr, 100.0, 100.0);
cairo_line_to(cr, 500, 500);
cairo_stroke(cr);
unsigned char* data;
data = cairo_image_surface_get_data(surface);
SDL_Texture* texture;
SDL_Rect rect = {0, 0, 100, 100};
texture = SDL_CreateTexture(mainRenderer, SDL_PIXELFORMAT_ABGR8888,
SDL_TEXTUREACCESS_STREAMING, 100, 200);
SDL_UpdateTexture(texture, &rect, data, 400);
// Main program loop
while (1)
{
SDL_Event event;
if (SDL_PollEvent(&event))
{
if (event.type == SDL_QUIT)
{
SDL_DestroyRenderer(mainRenderer);
SDL_DestroyWindow(mainWindow);
SDL_Quit();
break;
}
}
SDL_RenderClear(mainRenderer);
SDL_RenderCopy(mainRenderer, texture, NULL, NULL);
SDL_RenderPresent(mainRenderer);
}
// Cleanup and quit
cairo_destroy(cr);
cairo_surface_destroy(surface);
Your texture is 100x200 and you're only updating its (0,0)(100,100) rectangle from cairo image data, but with cairo you only started drawing at (100,100), so entire area is black. In addition, your pitch when updating texture is incorrect - it is byte length of source data line; your cairo image have width of 1200 and its format requires 4 bytes per pixel; neglecting padding it is 1200*4, not 400 (note - if format is different, e.g. 3 bytes per pixel, padding may be important - refer to cairo documentation to check if it pads its rows if you're going to use that format). So there are two solutions:
Use cairo to produce full image you want, e.g. don't use (100,100) offset with move_to, or copy entire image to SDL texture. Then only correcting pitch is enough.
Copy part of cairo data to texture,
e.g.
const unsigned int bpp = 4;
const unsigned int pitch = 1200*bpp;
SDL_UpdateTexture(texture, &rect,
data // offset pointer to start at 'first' pixel you want to copy
+ 100*pitch // skip first 100 rows
+ 100*bpp, // and first 100 pixels
pitch // pitch is the same - it refers to source image, not destination
);
I have finally started getting used to SDL 2's basic functions for rendering and I have stumbled across a problem that I believe the public might be able to answer. In my code I generate some text and using some code from a tutorial, am able to load the text as a texture (namely Lazy foo's tutorial). This texture now has a width and a height based on font size and how much text was entered. Another function I use loads in a square made of fancy boardering that I wish to use as a menu. This square is 200x200. As an example, if the text texture is 100x160, I want the square to now render as perhaps a 120x180 image (essentially compressing it to be a similar size as the text texture.
tl;dr:
I have 200x200 square.
I have 100x160 text texture
I want to render 200x200 square as a 120x160 square and render 100x160 text inside square.
***loadFromRenderedText takes a ttf font, a string, and a color (RGBA) to create an image texture based on the string -> generates own width/height
menuTextTexture.loadFromRenderedText(menuFont, "Info Item Skill Back",menuTextColor);
menuSize.x = 0;
menuSize.y = 0;
menuSize.w = menuTextTexture.getWidth() + boarderW;
menuSize.h = menuTextTexture.getHeight() + boarderW;
***menuSize is an SDL_Rect
menuBoxTexture.TextRender(XmenuRenderLocX, XmenuRenderLocY, &menuSize, 0, NULL, SDL_FLIP_NONE);
menuTextTexture.render(XmenuRenderLocX+boarderW, XmenuRenderLocY+boarderW);
TextRender and render do the same thing except render uses a scaling factor to multiply the clip size to be bigger (which I leave blank -> clip is then NULL and the basic height/width are used). For TextRender, I specify the render dimensions by passing the menuSize SDL rect. this takes the 200x200 square and renders only the 120x160 of the square at the (XmenuRenderLocX, XmenuRenderLocY)... thus essentially cropping the square, which is not what I want... I want to resize the square.
Any help will be greatly appreciated
Originally, I was using the provided LTexture::render function that was created for Lazy Foo's tutorial. See below code
void LTexture::render( int x, int y, SDL_Rect* clip, double angle, SDL_Point* center, SDL_RendererFlip flip )
{
//Set rendering space and render to screen
SDL_Rect renderQuad = { x, y, mWidth, mHeight };
//Set clip rendering dimensions
if( clip != NULL )
{
renderQuad.w = SCALE_SIZE*(clip->w);
renderQuad.h = SCALE_SIZE*(clip->h);
}
else if(mTexture ==NULL)
{
printf("Warning: Texture to Render is NULL!\n");
}
//Render to screen
SDL_RenderCopyEx( gRenderer, mTexture, clip, &renderQuad, angle, center, flip );
}
But because I didn't fully understand until now how exactly the function renders, I wasn't actually telling it to render at a new dimension (except in the case where I magnify everything with a SCALE_SIZE)
I made a new function for more control
void LTexture::DefinedRender(SDL_Rect* Textureclip, SDL_Rect* renderLocSize, double angle, SDL_Point* center, SDL_RendererFlip flip)
{
//Set clip rendering dimensions
if(mTexture ==NULL)
{
printf("Warning: Texture to Render is NULL!\n");
}
//Render to screen
SDL_RenderCopyEx( gRenderer, mTexture, Textureclip, renderLocSize, angle, center, flip );
}
And now everything works like I want it to.
I am just trying to scale (make bigger proportionally) my character based on windows weight and height. How can I do that?
I tried SDL_BlitScaled(newsurface, NULL, screen, NULL); but it did not work.
My code:
SDL_Surface* screen = SDL_GetWindowSurface(win);
SDL_Surface* mySprite = IMG_Load( SPRITE_PNG_PATH);
SDL_Rect rcSprite;
rcSprite.x = 250;
rcSprite.y = 100;
SDL_BlitSurface(mySprite, NULL, screen, &rcSprite);
The best way to accomplish this is to have a middle surface, whose width and height are your game's native resolution. You then render the entire frame to this surface, and render that surface to the window using the SDL_BlitScaled function.
For example, if you want your native resolution to be 600x400, you would create a 600x400 surface, blit your character and whatever else to that surface, and then finally scaled blit that surface to the window. If you resize your window to 1200x800, everything will look twice as big.
SDL_Surface* screen = SDL_GetWindowSurface(win);
// Create a surface with our native resolution
int NATIVE_WIDTH = 600;
int NATIVE_HEIGHT = 400;
SDL_Surface* frame = SDL_CreateRGBSurface(0, NATIVE_WIDTH, NATIVE_HEIGHT,
screen->format->BitsPerPixel, screen->format->Rmask,
screen->format->Gmask, screen->format->Bmask, screen->format->Amask);
assert(frameSurface);
SDL_Surface* mySprite = IMG_Load( SPRITE_PNG_PATH);
SDL_Rect rcSprite;
rcSprite.x = 250;
rcSprite.y = 100;
// Blit everything to the intermediate surface, instead of the screen.
SDL_BlitSurface(mySprite, NULL, frame, &rcSprite);
// Once we've drawn the entire frame, we blit the intermediate surface to
// the window, using BlitScaled to ensure it gets scaled to fit the window.
SDL_BlitScaled(frame, NULL, screen, NULL);
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.
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.