I made a C++ program that uses SDL for display and sound. I am implementing gtest to test the graphical functions, for example to draw a pixel :
void Interface::draw_pixel(unsigned short x, unsigned short y, bool on) {
if (on) {
SDL_SetRenderDrawColor(renderer, 255, 255, 255, SDL_ALPHA_OPAQUE);
} else {
SDL_SetRenderDrawColor(renderer, 0, 0, 0, SDL_ALPHA_OPAQUE);
}
SDL_Rect rect = {normalize_x(x), normalize_y(y), SIZE_MULTIPLIER_, SIZE_MULTIPLIER_};
SDL_RenderFillRect(renderer, &rect);
}
And to check if this pixel is indeed drawn :
bool Interface::is_pixel_on(int x, int y) {
p_ = (uint8_t *) SDL_GetWindowSurface(window)->pixels + normalize_y(y) * SDL_GetWindowSurface(window)->pitch +
normalize_x(x) * bpp_;
SDL_GetRGB(*(uint32_t *) p_, SDL_GetWindowSurface(window)->format, &rgb_.r, &rgb_.g, &rgb_.b);
return rgb_.r != 0;
}
I would like to draw a pixel and check if it is drawn in C.I. tests. I have tried to create the SDL window with the SDL_WINDOW_HIDDEN flag but it doesn't draw and my test fail.
Do you have any idea or hints how it should be done?
Generally, unit tests don't test gui but logics.
Have a layer of abstraction between library and your logic.
Eg:
namespace mygui
{
RenderFillRect(MyRenderer renderer, MyRect* rect);
};
void Interface::draw_pixel(unsigned short x, unsigned short y, bool on) {
if (on) {
MySetRenderDrawColor(renderer, 255, 255, 255, SDL_ALPHA_OPAQUE);
} else {
MySetRenderDrawColor(renderer, 0, 0, 0, SDL_ALPHA_OPAQUE);
}
MyRect rect = {normalize_x(x), normalize_y(y), SIZE_MULTIPLIER_, SIZE_MULTIPLIER_};
MyRenderFillRect(renderer, &rect);
}
Mock mygui::RenderFillRect and check if it's called with correct arguments after calling Interface::draw_pixel.
After your elaborated in comment about testing for CHIP8 interpreter, my suggestion is still relevant.
I'll suggest you to mock SDL function calls by using the instruction here.
Another way is mocking Interface::draw_pixel() to make sure one instruction is writing to the correct position.
I'm not sure when do you need to test SDL library. The only scenario I came up with is that it might breaks when you upgrade the library version. However most of time it doesn't get upgraded frequently.
Related
Are there layers to sdl or something?
by layers I mean like in photoshop we have multiple layer and can draw on one without effecting the other,
for example if I had a main_layer , a background_layer & an enemy_layer where the main player reandering (like moving the character by user), a static background rendering & enemies rendering can take place respectively?
instead of having to clear the entire screen then placing everything back again over and over? i.e. changing a single thing without effecting the other? can someone point me in the right direction?
You can implement your own layer system using render targets.
Create a texture render target for each layer.
Draw to a layer's render target to update it.
Every frame, draw each layer to the screen. You still need to clear the final frame beforehand.
It's worth noting that there is a point of diminishing return here. If a layer only contains a few sprites, it's probably cheaper to draw each sprite directly to the screen every frame even if they don't move.
Example:
// Given a renderer
SDL_Renderer *renderer = ...;
// *** Creating the layer ***
SDL_Texture *my_layer = SDL_CreateTexture(
renderer,
SDL_PIXELFORMAT_RGBA8888,
SDL_TEXTUREACCESS_TARGET,
screen_width, screen_height);
// To make transparency work (for non-base layers):
SDL_SetTextureBlendMode(my_layer, SDL_BLENDMODE_BLEND);
// *** Drawing TO the layer ***
SDL_SetRenderTarget(renderer, my_layer);
// For non-base layers, you want to make sure you clear to *transparent* pixels.
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 0);
SDL_RenderClear(renderer);
// ... Draw to the layer ...
// *** Drawing the layer to the screen / window ***
SDL_SetRenderTarget(renderer, NULL);
SDL_RenderCopy(renderer, my_layer, NULL, NULL);
You can take this a bit further by creating layers that are larger than screen_width x screen_height and use the srcrect parameter of SDL_RenderCopy() to scroll the layer. With a few background layers, that can be used to get efficient and neat-looking old-school parallax effects.
You will also probably want to encapsulate the notion of a layer into some Layer class in C++. Here's a rough starting point:
class Layer {
public:
Layer(SDL_Renderer *renderer, int w, int h)
: texture_(SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, w, h),
, display_{0, 0, 0, 0}
{
SDL_GetRendererOutputSize(renderer, &display_.w, &display_.h);
w = std::min(w, display_.w);
h = std::min(h, display_.h);
max_scroll_x = w - display_.w;
max_scroll_y = h - display_.h;
SDL_SetTextureBlendMode(texture_, SDL_BLENDMODE_BLEND);
}
Layer(Layer&& rhs)
: texture_(rhs.texture_)
, display_(rhs.display)
, max_scroll_x(rhs.max_scroll_x)
, max_scroll_y(rhs.max_scroll_y) {
rhs.texture_ = nullptr;
}
Layer& operator=(const Layer& rhs) {
if(texture_) {SDL_DestroyTexture(texture_);}
texture_ = rhs.texture_;
display_ = rhs.display_;
max_scroll_x = rhs.max_scroll_x;
max_scroll_y = rhs.max_scroll_y;
rhs.texture_ = nullptr;
)
Layer(const Layer& rhs) = delete;
Layer& operator=(const Layer& rhs) = delete;
~Layer() {
if(texture_) {SDL_DestroyTexture(texture_);}
}
// Subsequent draw calls will target this layer
void makeCurrent(SDL_Renderer* renderer) {
SDL_SetRenderTarget(renderer, texture_);
}
// Draws the layer to the currently active render target
void commit(SDL_Renderer* renderer, const SDL_Rect * dstrect=nullptr) {
SDL_RenderCopy(renderer, texture_, &display_, dstrect);
}
// Changes the offset of the layer
void scrollTo(int x, int y) {
display_.x = std::clamp(x, 0, max_scroll_x);
display_.y = std::clamp(y, 0, max_scroll_y);
}
private:
SDL_Texture* texture_;
SDL_Rect display_;
int max_scroll_x;
int max_scroll_y;
};
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 to create an entity with Qt3D that has a custom image as texture. I came across the QPaintedTextureImage (link leads to Qt 5.9 version for details. Here ist doc for 5.8), which can be written with a QPainter but I don't understand how.
First, this is how I imagine the entity could look like:
[EDIT]: code is edited and works now!
planeEntity = new Qt3DCore::QEntity(rootEntity);
planeMesh = new Qt3DExtras::QPlaneMesh;
planeMesh->setWidth(2);
planeMesh->setHeight(2);
image = new TextureImage; //see below
image->setSize(QSize(100,100));
painter = new QPainter;
image->paint(painter)
planeMaterial = new Qt3DExtras::QDiffuseMapMaterial;
planeMaterial->diffuse()->addTextureImage(image);
planeEntity->addComponent(planeMesh);
planeEntity->addComponent(planeMaterial);
TextureImage is the subclassed QPaintedTextureImage with paint function:
class TextureImage : public Qt3DRender::QPaintedTextureImage
{
public:
void paint(QPainter* painter);
};
What does the QPainter, passed to paint function, need to do in the implementation of paint if I just want to draw a big circle to the planeEntity?
[Edit] Implementation:
void TextureImage::paint(QPainter* painter)
{
//hardcoded values because there was no device()->width/heigth
painter->fillRect(0, 0, 100, 100, QColor(255, 255, 255));
/* Set pen and brush to whatever you want. */
painter->setPen(QPen(QBrush(QColor(255, 0, 255)) ,10));
painter->setBrush(QColor(0, 0, 255));
/*
* Draw a circle (or an ellipse -- the outcome depends very much on
* the aspect ratio of the bounding rectangle amongst other things).
*/
painter->drawEllipse(0, 0, 100, 100);
}
The short answer is... use QPainter exactly the same way you would normally.
void TextureImage::paint (QPainter* painter)
{
int w = painter->device()->width();
int h = painter->device()->height();
/* Clear to white. */
painter->fillRect(0, 0, w, h, QColor(255, 255, 255));
/* Set pen and brush to whatever you want. */
painter->setPen(QPen(QBrush(QColor(0, 0, 0)) ,10));
painter->setBrush(QColor(0, 0, 255));
/*
* Draw a circle (or an ellipse -- the outcome depends very much on
* the aspect ratio of the bounding rectangle amongst other things).
*/
painter->drawEllipse(0, 0, w, h);
}
However, note that you really shouldn't invoke the paint method directly. Instead use update which will cause Qt to schedule a repaint, initialize a QPainter and invoke your overridden paint method with a pointer to that painter.
It might be simpler to dynamically load the image you need in QML.
I had to do it not so long ago and opened a question on SO for it:
Qt3D dynamic texture
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.
How does one draw with pixels in SDL2.0?
I'm trying to get familiar with C++, but this is very difficult to do without pretty pictures, so I'm trying to get a very basic graphics display thing running. All I really want it to do is give me a window, let me draw rgbα pixels on it, and access information about those pixels. There may be other things I want that I'm not aware of, but that's all that's on my list right now. My research on this has lead me to try using SDL, the current version being 2.0.
Almost all my graphics experience comes from using JavaScript on a <canvas>. Most of the other bit comes from my calculator, which has this really awesome Pxl-On() command, so easy.
I'm using MinGW for my C++, if it matters. Also, if there's something better** out there than SDL2.0 for what I need, advice welcome.
** "better" means "contains what functionality I need, but less total functionality than SDL2.0, and/or has a more intuitive/less complex*** API than SDL2.0."
*** Less lines of code to accomplish the same task.
Runnable example
Draws a diagonal red line pixel by pixel on the screen using SDL_RenderDrawPoint.
main.c
#include <stdlib.h>
#include <SDL2/SDL.h>
#define WINDOW_WIDTH 600
int main(void) {
SDL_Event event;
SDL_Renderer *renderer;
SDL_Window *window;
int i;
SDL_Init(SDL_INIT_VIDEO);
SDL_CreateWindowAndRenderer(WINDOW_WIDTH, WINDOW_WIDTH, 0, &window, &renderer);
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 0);
SDL_RenderClear(renderer);
SDL_SetRenderDrawColor(renderer, 255, 0, 0, 255);
for (i = 0; i < WINDOW_WIDTH; ++i)
SDL_RenderDrawPoint(renderer, i, i);
SDL_RenderPresent(renderer);
while (1) {
if (SDL_PollEvent(&event) && event.type == SDL_QUIT)
break;
}
SDL_DestroyRenderer(renderer);
SDL_DestroyWindow(window);
SDL_Quit();
return EXIT_SUCCESS;
}
GitHub upstream.
Compile and run:
gcc -std=c89 -Wextra -pedantic-errors -o main.out main.c -lSDL2
./main.out
If you want to set a large rectangle of pixels at once, e.g. the entire screen or a sprite, use SDL_Texture + SDL_RenderCopy and possibly SDL_TEXTUREACCESS_STREAMING, as that will be much faster. Examples at:
What is a Blit in SDL?
Rendering pixels from array of RGB values in SDL 1.2?
Tested on libsdl 2.0.2, Ubuntu 15.10.
I don't know how your code is structured. Assuming you have a SDL_Window and a SDL_Renderer, you just have to call SDL_RenderDrawPoint(renderer, x, y).
If you don't have a renderer nor window, you can create both with SDL_CreateWindowAndRenderer(). For example:
SDL_Window *window;
SDL_Renderer *renderer;
SDL_CreateWindowAndRenderer(800, 600, 0, &window, &renderer);
//Probably on a loop
SDL_RenderDrawPoint(renderer, 400, 300); //Renders on middle of screen.
SDL_RenderPresent(renderer);
This should draw a pixel on the middle of screen. To read a pixel is a little more complicated. You can use SDL_RenderReadPixels(), it is made for read an area, but you can always specify an area of 1x1. Read the wiki page if you really need it.
If you are having much trouble with SDL2 a recommend you to read the Lazy Foo tutorials. The SDL2 section still a work in progress, but there is enough material to begin learning.
I find Python + PySDL2 more easy to prototype with. Debug is also funny, because it is veeeery slooow for pixel graphics. =) Here is the complete code:
"""
The code is placed into public domain
by anatoly techtonik <techtonik#gmail.com>
"""
import sdl2
import sdl2.ext
sdl2.ext.init()
window = sdl2.ext.Window('', size=(300, 100))
window.show()
renderer = sdl2.ext.Renderer(window)
renderer.draw_point([10,10], sdl2.ext.Color(255,255,255))
renderer.present()
running = True
while running:
for e in sdl2.ext.get_events():
if e.type == sdl2.SDL_QUIT:
running = False
break
if e.type == sdl2.SDL_KEYDOWN:
if e.key.keysym.sym == sdl2.SDLK_ESCAPE:
running = False
break