EDIT: SOLVED
The problem was me using the renderstate functions I needed for alphablending outside of the Sprite->Begin() and Sprite->End() codeblock.
I am creating my own 2D engine within DirectX 9.0. I am using sprites with corresponding spritesheets to draw them. Now the problem is, if I set my blending to D3DSPR_SORT_TEXTURE, I'll be able to see the texture without any problems (including transformation matrices), however if I try and set it to D3DSPR_ALPHABLEND, the sprite won't display. I've tried several things; SetRenderState, change the image format from .png to .tga, add an alpha channel to the image with a black background, used another image used within an example of 2D blending, changed my D3DFMT_ parameter of my D3DManager, etc.
I'm tried searching for an answer here but didn't find any answers related to my question.
Here's some of my code which might be of importance;
D3DManager.cpp
parameters.BackBufferWidth = w; //Change Direct3D renderer size
parameters.BackBufferHeight = h;
parameters.BackBufferFormat = D3DFMT_UNKNOWN; //Colors
parameters.BackBufferCount = 1; //The amount of buffers to use
parameters.MultiSampleType = D3DMULTISAMPLE_NONE; //Anti-aliasing quality
parameters.MultiSampleQuality = 0;
parameters.SwapEffect = D3DSWAPEFFECT_DISCARD;
parameters.hDeviceWindow = window; //The window to tie the buffer to
parameters.Windowed = true; //Window mode, true or false
parameters.EnableAutoDepthStencil = NULL;
parameters.Flags = NULL; //Advanced flags
parameters.FullScreen_RefreshRateInHz = 0; //Fullscreen refresh rate, leave at 0 for auto and no risk
parameters.PresentationInterval = D3DPRESENT_INTERVAL_ONE; //How often to redraw
Sprite.cpp
void Sprite::draw(){
D3DXVECTOR2 center2D = D3DXVECTOR2(center.x,center.y);
D3DXMatrixTransformation2D(&matrix,¢er2D,NULL,&scale,¢er2D,angle,new D3DXVECTOR2(position.x,position.y));
sprite->SetTransform(&matrix);
sprite->Begin(D3DXSPRITE_ALPHABLEND);
if(!extended){
sprite->Draw(texture, NULL, NULL, &position, 0xFFFFFF);
}
else{
doAnimation();
sprite->Draw(texture, &src, ¢er, new D3DXVECTOR3(0,0,0), color);
}
sprite->End();
}
Main.cpp
//Clear the scene for drawing
void renderScene(){
d3dManager->getDevice().Clear(0,NULL,D3DCLEAR_TARGET,0x161616,1.0f,0); //Clear entire backbuffer
d3dManager->getDevice().BeginScene(); //Prepare scene for drawing
render(); //Render everything
d3dManager->getDevice().EndScene(); //Close off
d3dManager->getDevice().Present(NULL, NULL, NULL, NULL); //Present everything on-screen
}
//Render everything
void render(){
snake->draw();
}
I've got no clue at all. Any help would be appreciated.
The problem was me using the renderstate functions I needed for alphablending outside of the Sprite->Begin() and Sprite->End()
code block.
Related
im currently facing an strange error with rendering text using SDL_TTF and OpenGL.
The thing is that when i use TTF_RenderText_Blended , all texts are displayed good and without any problems
But when i want switch to TTF_RenderText_Solid "buggy" black rectangles are displayed and i dont know specify if its problem with SDL_TTF or in OpenGL when creating the right texture from surface
Function to load surface from textInfo(font,size)
void TextSprite::loadSprite(const std::string& text, textInfo* info){
SDL_Surface* tmpSurface = nullptr;
tmpSurface = TTF_RenderText_Solid(info->font,text.c_str(), *_color);
if (tmpSurface==nullptr){
ErrorManager::systemError("Cannot make a text texture");
}
createTexture(tmpSurface);
}
Function to create an OpenGL texture from SDL_Surface
void TextSprite::createTexture(SDL_Surface* surface){
glGenTextures(1,&_textureID);
glBindTexture(GL_TEXTURE_2D,_textureID);
int Mode = GL_RGB;
if (surface->format->BytesPerPixel==4){
Mode = GL_RGBA;
}
glTexImage2D(GL_TEXTURE_2D,0,Mode,surface->w,surface->h,0,Mode,GL_UNSIGNED_BYTE,surface->pixels);
//Wrapping
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_REPEAT);
//Filtering
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR_MIPMAP_NEAREST);
glBindTexture(GL_TEXTURE_2D,0);
_rect.w = surface->w;
_rect.h = surface->h;
SDL_FreeSurface(surface);
}
Thanks for help.
TTF_RenderText_Solid() outputs 8-bit palettized surfaces, not the 32-bit ARGB surfaces that TextSprite::createTexture() operates on.
class Pong {
public:
Pong(int speed) {
gSpeed = speed;
gPongBG = SDL_LoadBMP("pongBG.bmp");
gPongBGSurf = gPongBG;
gPongRect.w = 800;
gPongRect.h = 460;
gPongRect.x = 700;
gPongRect.y = 220;
gPongPlayer = SDL_LoadBMP("pongPlayer.bmp");
gPongPlayerRect.h = 50;
gPongPlayerRect.w = 10;
gPongPlayerRect.x = 50;
gPongPlayerRect.y = 0;
}
~Pong() {
}
void drawPong() {
gPongBGSurf = gPongBG;
SDL_BlitSurface(gPongBGSurf, NULL, gScreenSurface, &gPongRect);
SDL_BlitSurface(gPongPlayer, NULL, gPongBGSurf, &gPongPlayerRect);
}
void movePlayer() {
gPongPlayerRect.y++;
}
The following code makes it so the gPongPlayerRect makes multiple copies of itself, rather than moving it as i planned. Later in the code, i update the main window named gWindow, and the surface of the main window is the wScreenSurface. If i blit the player directly onto the Window surface, it moves, so i guess the problem is that the old gPongBGSurf surface stays even tho its updated. How could i eventually fix this? Thanks!
My guess is that you forgot to erase the Pong Surface:
Uint32 black= SDL_MapRGBA(gPongBGSurf->format,0,0,0,255);
SDL_FillRect(gPongBGSurf, NULL, black);
SDL_BlitSurface(gPongPlayer, NULL, gPongBGSurf, &gPongPlayerRect);
SDL_BlitSurface(gPongBGSurf, NULL, gScreenSurface, &gPongRect);
For a full example of a SDL2 game with multiple surfaces blitting on top of each other and then onto a screen surface, you can read the small source code of Rock Dodger CE which is only a single file.
I've been working on a project in SDL on nights and weekends for the past few months. I'm currently trying to get a menu system working. At the moment, I'm working on drawing text using SDL_TTF. As for my question, I'm seeing some strange behavior when I try to draw some textures to another texture.
The weirdness is that when I draw it, on a destination texture created with SDL_TEXTUREACCESS_TARGET (like it says to do in the docs) draws nothing, but returns no error. However, if I use SDL_TEXTUREACCESS_STATIC or SDL_TEXTUREACCESS_STREAM, it returns an error when I set the render target because of the access attribute, but draws just fine. After doing some digging, I heard some things about a bug in the Intel drivers (I'm on a Macbook with Intel graphics), so I was wondering if this was something I messed up, and how I might fix it. Alternately, if it isn't my fault, I'd still like to know what's going on, and if it would perform differently on different platforms and how I could work around it.
Here's my code, after removing unnecessary parts and :
I create the renderer:
renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_TARGETTEXTURE);
Later on, when I go to render onto a canvas:
TTF_Font *fnt = loadFont(fontName.c_str(), fontSize);
In here I parse out some attributes and set them using TTF_SetFontStyle() and the clr for text color.
SDL_Texture *canvas;
canvas = SDL_CreateTexture(rendy, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, contentRect.w, contentRect.h)
SDL_SetRenderTarget(rendy, canvas);
int pos = 0;
for (list<string>::iterator itr = lines.begin(); itr != lines.end(); itr++){
SDL_Surface *temp;
temp = TTF_RenderText_Blended(fnt, src.c_str(), clr);
SDL_Texture *line;
line = SDL_CreateTextureFromSurface(rendy, temp);
int w,h;
SDL_QueryTexture(line, NULL, NULL, &w, &h);
SDL_Rect destR;
//Assume that we're left justified
destR.x = 0;
destR.y = pos;
destR.w = w;
destR.h = h;
SDL_RenderCopy(rendy, line, NULL, &destR);
SDL_DestroyTexture(line);
SDL_FreeSurface(temp);
pos += TTF_FontLineSkip(fnt);
}
//Clean up
SDL_SetRenderTarget(rendy, NULL);
canvas gets returned to the calling function so it can be cached until this text box is modified. That function works by having a texture for the whole box, drawing a background texture onto it, and then drawing this image on top of that, and holding on to the whole thing.
That code looks like this:
(stuff to draw the background, which renders fine)
SDL_Texture *sum = SDL_CreateTexture(rendy, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, globalRect.w, globalRect.h);
SDL_SetTextureBlendMode(sum, SDL_BLENDMODE_BLEND);
SDL_SetRenderTarget(rendy, sum);
string lPad = getAttribute(EL_LEFT_PADDING);
string tPad = getAttribute(EL_TOP_PADDING);
int paddingL = strtol(lPad.c_str(), NULL, 10);
int paddingT = strtol(tPad.c_str(), NULL, 10);
SDL_Rect destR;
SDL_Rect srcR;
srcR.x = 0;
srcR.y = 0;
srcR.w = globalRect.w; //globalRect is the size size of the whole button
srcR.h = globalRect.h;
destR.x = 0;
destR.y = 0;
destR.w = globalRect.w;
destR.h = globalRect.h;
SDL_RenderCopy(rendy, bgTexture, NULL, &destR);
int maxX = contentRect.w;
fgTexture = getFGImage(rendy); //The call to the previous part
int w, h;
SDL_QueryTexture(fgTexture, NULL, NULL, &w, &h);
int width, height;
getTextSize(&width, &height, maxX);
srcR.x = 0;
srcR.y = 0;
srcR.w = width;
srcR.h = height;
destR.x = paddingL;
destR.y = paddingT;
destR.w = globalRect.w;
destR.h = globalRect.h;
SDL_RenderCopy(rendy, fgTexture, NULL, &destR);
SDL_DestroyTexture(fgTexture);
SDL_DestroyTexture(bgTexture);
return sum;
Sum is returned to another function which does the drawing.
Thanks in advance!
Update
So I've figured out that the reason it only drew when I had the incorrect access setting was that, since the function was returning an error value, the render target was never set to the texture, so it was just drawing on the screen. I've also checked all my textures by writing a function AuditTexture which checks to see that the texture format for a texture is supported by the renderer, prints a string description of the access attribute, and prints the dimensions. I now know that all of their texture formats are supported, the two lines are static, canvas and sum are render targets, and none of them have dimensions of zero.
As it turns out, I had set the render target to be the composite texture, then called my function which set the render target to the text texture before drawing text. Then when I returned from the function, the render target was still the text texture instead of the composite one, so I basically drew the text over itself instead of drawing over the background.
A word to the wise: Don't ever assume something is taken care of for you, especially in c or c++.
I'm trying to display a texture onto the screen but all I'm getting is a black window.
No SDL Errors are being reported. There's a good chance that I'm missing something stupid, but I can't see it. Hopefully another set of eyes will help. Feel free to ask for more code/info.
main.cpp
SDL_Window * window;
SDL_Renderer * renderer;
SDL_Texture * grass;
SDL_Rect g_dst;
SDL_Event event;
Game app;
SDL_Init(SDL_INIT_EVERYTHING);
window = SDL_CreateWindow("tmp", 100, 100, 640, 480, SDL_WINDOW_SHOWN);
renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
g_dst.x = g_dst.y = 0;
g_dst.w = 640;
g_dst.h = 480;
grass = IMG_LoadTexture(renderer, "grass.bmp");
while (app.isRunning()) {
app.pollEvents(&event);
app.render_init();
app.render(grass, NULL, &g_dst);
app.render_end();
}
//SDL_Quit() is handled by the Game class' destructor
Game.cpp
//Only functions used for rendering are shown
void render_init(Uint8 red=0, Uint8 green=0, Uint8 blue=0, Uint8 alpha=255)
{
SDL_SetRenderDrawColor(renderer, red, green, blue, alpha);
SDL_RenderClear(renderer);
}
void render(SDL_Texture * texture, SDL_Rect * src, SDL_Rect * dest) {
SDL_RenderCopy(renderer, texture, src, dest);
}
void render_end() { SDL_RenderPresent(renderer); }
First of all, you're initializing everything? please don't do that frequently, mind you that you're also initializing MANY unnecessary stuffs like for game controllers, etc. if the app gets bigger then the efficiency and the possibility of this app running at a smoot speed is at stake.
I also noticed that you are declaring variables in the .cpp file, do that in the header file and just recall the header to the cpp file that will be using it.
You want to render the grass right? and render it as much as the screens size.
(I'll just assume that you used this in the game.cpp part, which is the very first file, thus, not regarding any classes made)
int winWidth = 680; //The reason for this is just in case you make the window resizable
int winHeight = 480; //then the texture would also resize along with the window
SDL_Window *window = window = SDL_CreateWindow("The Space Project", 100, 100, winWidth, winHeight, SDL_WINDOW_SHOWN);
SDL_Renderer *renderer = NULL; //I've set this to NULL so that we can know if
the reason as to why your image is not rendering is because the renderer is not properly working.
renderer = SDL_CreateRenderer( window, -1, SDL_RENDERER_ACCELERATED);
if(renderer == NULL)
{
cout >> "Renderer is not working" >> endl;
//This shows a line at the command prompt that your renderer doesn't have any output, thus, only having a NULL as an equivalent
}
SDL_Texture* grass= NULL;
grass= IMG_LoadTexture(renderer, "grass.bmp"); //As you can see, I've set the grass to Null again
if(grass == NULL)
{
cout >> "Grass have failed to initialize" >> endl;
/*I don't normally do this but it's very important if you really need trouble shooting guides
but this time, were here to check IF the grass.bmp entered the SDL_Texture grass, so if the system can't find the .bmp file then it would show this error
since the grass (SDL_Texture) still doesn't have anything inside it (NULL)*/
}
SDL_Rect grass_rect;
grass_rect.x = 0;
grass_rect.y = 0;
grass_rect.w = winWidth;
grass_rect.h = winHeight;
//Loop part, I'll skip some of it
while (!quit && mainEvent->type != SDL_QUIT) //!quit is just an imaginary Boolean I've typed)
{
SDL_PollEvent(mainEvent); //Let's say you created the event already
SDL_RenderClear(renderer);
SDL_RenderCopy(renderer, grass, NULL, &grass_rect);
//The NULL part is also similar to a rect but it's a limiting type, we didn't assign anything to it
since I assumed that you wanted the whole image to be rendered
SDL_RenderPresent(renderer);
}
I revised the code and made it more efficient since your code called for useless extras which might result in lower performance.
I also notice that you tried calling for color changes?
use this
SDL_SetTextureColorMod(texture, red-value, green-value, blue-value);
and put it in the loops part under the render present of the same texture.
SDL_SetTextureColorMod(grass, 250, 250, 250);
Doing this would set all color values to 250, thus, having a white color, this change your texture color to white.
You're also wasting space on making the app.is running(), you could easily replace it with a boolean, which consumes much less space or you could omit it if you don't have an exit button inside the application and just make your loop read the SDL_QUIT, this saves space for the file, mind the efficiency.
If this still doesn't work then try replacing the image your using, make a simple one on paint name it something like "grass.png" or anything then try it again.
Don't forget to put the file in the proper folder, in the DEBUG folder if you haven't specified a folder, and also put it in the app folder so it would also read it when it executes as an .exe file and not as part of the debug command.
I'm attemting to load an image that I exported from flash CS3 it's a very cute face but it loads very weird it loads on a blueish way this is the code for the two files:
//main.cpp
#include <SDL/SDL.h>
#include <SDL/SDL_image.h>
#include "test.hpp"
int main(int argc, char *argv[])
{
SDL_Init(SDL_INIT_VIDEO);
// Activamos modo de video
screen = SDL_SetVideoMode(640,480,32,SDL_SWSURFACE | SDL_DOUBLEBUF);
image = IMG_Load("face.bmp");
dest.x = 200;
dest.y = 200;
//Main Loop
while(Abierto)
{
//We Draw
Draw();
//Events
while( SDL_PollEvent(&event))
{
if(event.type == SDL_QUIT)
Abierto = false;
}
}
// We free the image
SDL_FreeSurface(image);
SDL_Quit();
return 0;
}
Now the other one the;
//test.hpp
DL_Surface *image = NULL, *screen = NULL;
SDL_Rect dest;
SDL_Event event;
bool Abierto = true;
float PlaneX = 300, PlaneY = 200;
float velX = 0.1, velY = 0.1;
void Draw()
{
Uint32 color;
// Black Background is created
color = SDL_MapRGB (screen -> format, 0, 0, 0);
SDL_FillRect (screen, NULL, color);
SDL_DisplayFormatAlpha(image);
SDL_BlitSurface(image, NULL, screen, &dest);
// Flip the working image buffer with the screen buffer
SDL_Flip (screen);
}
I need help with this please Im not that experienced on SDL stuff oh and if you want to take a closer look I uplaoded the project here.
Oh my bad I must add the image is 32 pixels with alpha according to flash exporting options
According to docs, SDL_DisplayFormatAlpha returns a new image and keeps the original intact.
So, try in the first part, when you load the image:
SDL_Surface *origImage = IMG_Load("face.bmp");
image = SDL_DisplayFormatAlpha(origImage);
SDL_FreeSurface(origImage)
As there is no need to call SDL_DisplayFormatAlpha each frame.
Then in the second part, just blit image, without calling SDL_DisplayFormatAlpha.
UPDATE
I've just checked your picture, and it looks like it is a weird bmp. I've seen that before: BMP format is such a mess that if you don't keep to the basics chances are that different programs will interpret the data differently.
In your case:
display face.bmp shows correctly.
gthumb face.bmp shows nothing.
eog face.bmp says "bogus header data".
I strongly recommend using PNG files for all your game cartoon-like pictures and JPG for all the photo-like ones.
So run
$ convert face.bmp face.png
And use the PNG file. I'll will work better and you will have a file 20% the size of the original.