Hey so I was trying to make a program where you can draw a line from a point to where your mouse is but I am having trouble figuring out how to delete the line after it has been drawn.
#include <allegro.h>
#include <cstdlib>
BITMAP *buffer;
int main()
{
allegro_init();
install_mouse();
install_keyboard();
set_color_depth(16);
set_gfx_mode(GFX_AUTODETECT, 640, 480, 0, 0);
buffer = create_bitmap(640, 480);
while (!key[KEY_ESC]) {
if (key[KEY_SPACE]) {
line(buffer, 30, 450, mouse_x, mouse_y, makecol(255, 0, 0));
}
draw_sprite(screen, buffer, 0, 0);
release_screen();
rest(10);
}
return 0;
}
END_OF_MAIN();
You will need to store the coordinates of the lines in a data structure of some sort (e.g., an array of structs). When you want to delete a line, remove it from the data structure.
Your drawing code then looks like:
Clear buffer
Iterate through every line, drawing it to buffer
Draw buffer to screen
And don't call acquire/release screen. They generally aren't needed, and you'll give yourself a lot of problems if you misuse them.
Related
I want to be able to draw all my text, lines , triangles and other stuff to screen and then clear the screen and draw something new, BUT this method makes the screen flicker, and all the drawings dont appear at the same time.
My idea is to draw to some kind of a buffer and then draw that buffer to the screen and clear the buffer, and repeat. This way the screen wont flicker and all will be drawn at the same time.
I am using windows.h , Visual Studio.
#include <Windows.h>
#include <iostream>
using namespace std;
struct vec2d
{
int x, y;
};
void Line(HDC dc, vec2d a, vec2d b)
{
MoveToEx(dc, a.x, a.y, NULL);
LineTo(dc, b.x, b.y);
}
vec2d GetMousePos(HWND console)
{
vec2d out;
POINT p;
GetCursorPos(&p);
out.x = p.x; out.y = p.y;
return out;
}
int main()
{
HWND console = GetConsoleWindow();
HDC dc = GetDC(console);
SelectObject(dc, CreatePen(PS_SOLID, 1, RGB(255, 255, 255)));
while (1)
{
//BitBlt(dc, 0, 0, 1000, 1000, 0, 0, 0, BLACKNESS); Flickering is much much bigger, because its faster
system("cls");
Line(dc, { 0, 0 }, GetMousePos(console));
}
}
Thanks in advance, Mark.
I don't think you have as much control over a console window as you would over your own HWND. I was able to eliminate the flicker in your code by replacing system("cls"); with InvalidateRect().
RECT client;
GetClientRect(console, &client);
while (1)
{
InvalidateRect(console, &client, TRUE);
Line(dc, console, { 0, 0 }, GetMousePos(console));
}
(You can probably improve this by only invalidating the area where the previous line was drawn.)
Also, one other change you can make (unrelated to flicker) is to add:
ScreenToClient(console, &p);
to GetMousePos() after you call GetCursorPos(&p);. This will map the pointer co-ords to the window instead of the screen.
Further reading on creating your own window: Creating a Window. Not as simple as using a console window, but you have much greater control.
I want my game engine to be nice and tidy and rather than coding a bunch of redundant lines, I would rather include functions that do this for me.
void draw::image(){
SDL_Surface *bmp = SDL_LoadBMP("C:\\Users\\Joe\\Documents\\Visual Studio 2013\\Projects\\SDL_APP1\\map1.bmp");
SDL_Texture*bmptx;
SDL_Renderer * renderer = SDL_CreateRenderer(_window, -1, 0);
bmptx = SDL_CreateTextureFromSurface(renderer, bmp);
SDL_FreeSurface(bmp);
SDL_RenderCopy(renderer, bmptx, NULL, NULL);
SDL_RenderPresent(renderer);
}
void draw::text(string q, float x, float y, float w, float h){
SDL_SetRenderDrawColor(renderer, 64, 64, 64, 255);
SDL_RenderDrawLine(renderer, x, y, w, h);
SDL_RenderPresent(renderer);
}
My problem is that I don't know how to format the text() function so that it draws to the same renderer as the image() function. I want it so that in my main loop, I can call both the text and the image functions and they will draw to the same renderer at the same time. This way I wont have to directly code these into my main loop. Side note I am using SDL 2.
You would want to pass a pointer to the renderer you previously created (probably in main()) to each of your drawing functions. Creating a new renderer for every object you draw would be very inefficient.
void draw::image(SDL_Renderer *renderer)
{
// ...
}
void draw::text(SDL_Renderer *renderer, string q, float x, float y, float w, float h)
{
SDL_SetRenderDrawColor(renderer, 64, 64, 64, 255);
// ...
}
Then, within your main() after you've created the window, you'd create your renderer:
renderer = SDL_CreateRenderer(win, -1, SDL_RENDERER_ACCELERATED);
and then pass it to your drawing functions. Assuming your methods are static, then:
draw::image(renderer);
or if you have an object on the stack:
myDrawObject.image(renderer);
or if you have a pointer to one of your draw objects:
myDrawPtr->image(renderer);
Also, you probably need to think about this approach a bit more. Presumably you want to draw these things every frame, so with your current approach you are requiring SDL to load the BMP file from disk (or disk cache) and convert it to whatever internal format it requires for the texture, every single frame. It's unlikely this will give you acceptable performance, especially when you want to render multiple images per frame.
More than likely, a better approach will be to store some of these resources in member variables within your draw class. But this is basic C++ stuff, so you might want to do some more reading and tutorials around the subject of classes.
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 would like to draw a polygon with repeat texture (e.g brick). Here is my code:
textureBrick = new Texture(Gdx.files.internal("data/brick.png"));
textureBrick.setWrap(TextureWrap.Repeat, TextureWrap.Repeat);
TextureRegion texreg = new TextureRegion(textureBrick,0,0,1f,1f);
texreg.setTexture(textureBrick);
PolygonRegion po = new PolygonRegion(texreg, floatvertices);
and next i draw (render):
public void render(SpriteBatch spriteBatch, PolygonSpriteBatch polygonBatch) {
Gdx.gl.glEnable(GL10.GL_TEXTURE_2D);
polygonBatch.draw(po, 0,0, 512f, 256f);
}
Unfortunately, I always gets polygons filled by white colour. Why?
You might be calling code in this order
spriteBatch.begin();
spriteBatch.draw(textureRegion, 0, 0, 480, 480);
polygonBatch.begin();
polygonBatch.draw(polygonRegion, 0,0, 400f, 400f);
polygonBatch.end();
spriteBatch.end();
Using spriteBatch,polygonBatch, shapeRenders etc together might lead to this type of problem you should use them seperately :
spriteBatch.begin();
spriteBatch.draw(textureRegion, 0, 0, 480, 480);
spriteBatch.end();
polygonBatch.begin();
polygonBatch.draw(polygonRegion, 0,0, 400f, 400f);
polygonBatch.end();
Before using begin of any other batch you should end the previous batch.
i'm fairly new at programming with allegro, and i wanna change the background color of my programs from something more pleasant than black haha :) can some one help please?
and just for a reference of what im doing
#include <allegro.h>
BITMAP* buffer;
BITMAP* bmp;
int cursor_x = 20;
int cursor_y = 20;
int getMouseInfo(){
if(mouse_b & 1){
cursor_x = mouse_x;
cursor_y = mouse_y;
return 1;
}
return 0;
}
void updateScreen(){
show_mouse(NULL);
circlefill ( buffer, cursor_x, cursor_y, 60, makecol( 0, 255 , 0));
draw_sprite( screen, buffer, 0, 0);
}
int main(){
allegro_init();
install_mouse();
install_keyboard();
set_color_depth(16);
set_gfx_mode( GFX_AUTODETECT, 640, 480, 0, 0);
rectfill (
buffer = create_bitmap( 640, 480);
show_mouse(screen);
while( !key[KEY_ESC])
{
int switcher=1;
while(getMouseInfo())
{
updateScreen();
if(getMouseInfo()==0) switcher=0;
}
if(switcher==0) show_mouse(screen);
}
return 0;
}
END_OF_MAIN();
To create backgroud bitmap try this:
/* Make a bitmap in RAM. */
BITMAP *bmp = create_bitmap(SCR_X, SCR_Y);
then try this to clear bmp to some different color:
/* Clear the screen to red. */
clear_to_color(bmp, makecol(255, 0, 0));
or this to load bitmap from file:
bmp = load_bitmap("image.pcx", palette);
Then you just need to blit this bitmap with your screen - like this:
/* Blit bmp on the screen. */
blit(bmp, screen, 0, 0, 0, 0, bmp->w, bmp->h);
Draw a screen-sized rectangle that is the color you want the background to be. Or just use clear_bitmap to clear the screen.
#include <iostream>
using namespace std;
int main()
{
cout<<" In the world were gamers play MINECRAFT, where they creating everithing they can emagine ...\n";
cin.get();
return 0;
}