I am trying to draw individual pixels to an SDL2 streaming texture. I am attempting to store my pixels in a std::vector and then lock my texture, update the texture then unlock, pass it to the renderer and the present it.
However, I am always getting a black screen. I have tried several permutations of the below code but I am at a loss.
#include "pch.h"
#include "Window.h"
Window::Window(unsigned int width, unsigned int height) :
m_width(width), m_height(height)
{
if (SDL_Init(SDL_INIT_VIDEO || SDL_INIT_TIMER) < 0)
{
std::cout << "SDL failed to initilize correct. Error: "
<< SDL_GetError << std::endl;
}
m_window = SDL_CreateWindow("Cotton Rasterizer - Hardeep Bahia 2021", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, m_width, m_height, 0);
if (m_window == NULL)
{
std::cout << "Window failed to initilize: " << SDL_GetError << std::endl;
}
m_renderer = SDL_CreateRenderer(m_window, -1, SDL_RENDERER_TARGETTEXTURE);
if (m_renderer == NULL)
{
std::cout << "Renderer failed to initilize: " << SDL_GetError << std::endl;
}
m_texture = SDL_CreateTexture(m_renderer, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_STREAMING, m_width, m_height);
if (m_texture == NULL)
{
std::cout << "Texture failed to initilize: " << SDL_GetError << std::endl;
}
auto p_format = SDL_GetWindowPixelFormat(m_window);
m_pixel_format = SDL_AllocFormat(p_format);
}
Window::~Window()
{
SDL_FreeFormat(m_pixel_format);
SDL_DestroyTexture(m_texture);
SDL_DestroyRenderer(m_renderer);
SDL_DestroyWindow(m_window);
}
void Window::test()
{
SDL_Rect filledRect = { m_width / 4, m_height / 4, m_width / 2, m_height / 2 };
SDL_SetRenderDrawColor(m_renderer, 255, 0, 0, 255);
SDL_RenderFillRect(m_renderer, &filledRect);
}
void Window::present()
{
SDL_RenderPresent(m_renderer);
}
void Window::clear()
{
SDL_SetRenderDrawColor(m_renderer, 0.f, 0.f, 0.f, 255.f);
SDL_RenderClear(m_renderer);
}
void Window::draw(const std::vector<Pixel>& i_pixels)
{
int pitch {(m_width * 4)};
std::vector<Uint32> pixels(m_width * m_height * 4, 0);
Uint32 color = SDL_MapRGBA(m_pixel_format, 255, 255, 255, 255);
for (auto& a : i_pixels)
{
unsigned int offset = (m_width * 4 * a.m_position.y) + a.m_position.x * 4;
pixels[offset + 0] = 255;
pixels[offset + 1] = 255;
pixels[offset + 2] = 255;
pixels[offset + 3] = 255;
}
unsigned char* locked_pixels{};
SDL_LockTexture(m_texture, NULL, reinterpret_cast<void **> (&locked_pixels) , &pitch);
std::memcpy(locked_pixels, pixels.data(), pixels.size());
SDL_UpdateTexture(m_texture, NULL, pixels.data(), pitch);
SDL_UnlockTexture(m_texture);
SDL_RenderCopy(m_renderer, m_texture, NULL, NULL);
}
My test function does draw, and is visible on the screen but it does not use the texture.
Resolved it by changing the draw function to as follow:
void Window::draw(const std::vector<Pixel>& i_pixels)
{
std::vector<unsigned char>pixels(m_width * m_height * 4, 0);
for (auto& i : i_pixels)
{
unsigned int x = i.m_position.x;
unsigned int y = i.m_position.y;
const unsigned int offset = (m_width * 4 * y) + (x * 4);
pixels[offset] = 255;
pixels[offset + 1] = 255;
pixels[offset + 2] = 255;
pixels[offset + 3] = 255;
}
unsigned char* lockedpixels = nullptr;
int pitch = (m_width * 4);
SDL_LockTexture(m_texture, NULL, reinterpret_cast<void**>(&lockedpixels), &pitch);
std::memcpy(lockedpixels, pixels.data(), pixels.size());
SDL_UpdateTexture(m_texture, NULL, pixels.data(), m_width * 4);
SDL_UnlockTexture(m_texture);
SDL_RenderCopy(m_renderer, m_texture, NULL, NULL);
}
Related
I'm trying to somehow get screenshot from uint8 array of RGB, but for example this code doesn't work:
#include <torch/torch.h>
#include <iostream>
#include <Windows.h>
#include <gdiplus.h>
#include <gdipluspixelformats.h> // PixelFormat24bppRGB
#include <vector>
#include <cstdlib>
#pragma comment(lib, "gdiplus.lib")
int main()
{
Gdiplus::GdiplusStartupInput input;
ULONG_PTR token;
Gdiplus::GdiplusStartup(&token, &input, NULL);
const int mWidth = 1920;
const int mHeight = 1080;
std::vector<uint8_t> pixels;
Gdiplus::BitmapData bmpData;
DWORD start = GetTickCount64();
HDC hdcScreen = GetDC(NULL);
BITMAPINFO bmpInfo;
bmpInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bmpInfo.bmiHeader.biWidth = mWidth;
bmpInfo.bmiHeader.biHeight = mHeight;
bmpInfo.bmiHeader.biPlanes = 1;
bmpInfo.bmiHeader.biBitCount = 24;
bmpInfo.bmiHeader.biCompression = BI_RGB;
HDC scComDC = CreateCompatibleDC(hdcScreen);
BitBlt(
scComDC,
0,0,
mWidth,
mHeight,
hdcScreen,
0,0,
SRCCOPY
);
LPDWORD lpPixel;
HBITMAP display = CreateDIBSection(scComDC, &bmpInfo, DIB_RGB_COLORS, (void**)&lpPixel, NULL, 0);
ReleaseDC(NULL,hdcScreen);
DeleteDC(scComDC);
LOGPALETTE lpPalette;
lpPalette.palVersion = 0x0300;
lpPalette.palNumEntries = 1;
lpPalette.palPalEntry[0].peRed =
lpPalette.palPalEntry[0].peGreen =
lpPalette.palPalEntry[0].peBlue =
lpPalette.palPalEntry[0].peFlags = NULL;
HPALETTE hPalette = CreatePalette(&lpPalette);
auto image = Gdiplus::Bitmap::FromHBITMAP(display, hPalette);
int bWidth = image->GetWidth();
int bHeight = image->GetHeight();
std::cout << image << std::endl;
std::cout << bWidth << std::endl;
std::cout << bHeight << std::endl;
auto stride = 3 * bWidth;
pixels.resize(stride * bHeight);
Gdiplus::Rect rect(0, 0, bWidth, bHeight);
image->LockBits(&rect, Gdiplus::ImageLockModeRead, PixelFormat24bppRGB, &bmpData);
for (int y = 0; y < bHeight; ++y) {
memcpy(pixels.data() + y * stride, (byte*)bmpData.Scan0 + y * bmpData.Stride, stride);
}
image->UnlockBits(&bmpData);
DWORD end = GetTickCount64();
std::cout << end - start << "ms\n";
while (true){
int inint;
std::cin >> inint;
if (inint == -1) {
break;
}
std::cout << ">> " << +pixels[inint*3]
<< "," << +pixels[inint * 3 + 1]
<< "," << +pixels[inint * 3 + 2]
<< "\n";
}
Gdiplus::GdiplusShutdown(token);
//system("PAUSE");
return 1;
}
I cannot successfully convert pixels to vector by running this program. It returns 0,0,0 indicating that all pixels are black.
I think I'm right around memcpy, since I was able to array successfully with
auto image = Gdiplus::Bitmap::FromFile(L"C:\sample.jpg");
but when I use Bitmap::FromHBITMAP(display, hPalette);, it doesn't work at all.
get screenshot from uint8 array of RGB
im using SDL2 and just grasped some of the basic-concepts of SDL TTF, but for some reason after a certain amount of time running the app, my text elements disappear with seemingly no reason why, can someone please tell me what i need to do to top my text renders from disappearing? what went wrong here?
#include <iostream>
#include <iomanip>
#include <SDL.h>
#include <SDL_ttf.h>
#include <SDL_image.h>
#include "AdviLib.h"
#define SDLKCM SDLK_COMMA
#define SDLKPR SDLK_PERIOD
#define SDLKSP SDLK_SPACE
#define SDLKES SDLK_ESCAPE
void Screenshot(SDL_Renderer* r, const char* name, int w, int h)
{
const uint32_t format{ SDL_PIXELFORMAT_ARGB8888 };
SDL_Surface* sur{ SDL_CreateRGBSurfaceWithFormat(0, w, h, 32, format) };
SDL_RenderReadPixels(r, NULL, format, sur->pixels, sur->pitch);
SDL_SaveBMP(sur, name);
SDL_FreeSurface(sur);
std::cout << name << " captured!\n";
}
int main(int args, char* argc[])
{
// before SDL init
std::cout << "enter the name of the session: "; string sesh{ sInput() };
std::cout << "enter the name of the local, non .bmp, image: "; string image{ sInput() };
// SDL init
SDL_Init(SDL_INIT_EVERYTHING);
IMG_Init(IMG_INIT_JPG | IMG_INIT_PNG);
TTF_Init();
const int W{ 800 }; const int H{ 750 };
SDL_Window* win{ SDL_CreateWindow(sesh.c_str(), SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, W, H, SDL_WINDOW_SHOWN) };
SDL_Renderer* ren{ SDL_CreateRenderer(win, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC) };
SDL_Surface* img{ IMG_Load(image.c_str()) };
TTF_Font* font{ TTF_OpenFont("CRYSRG__.ttf", 40) };
SDL_Color color{ 205, 99, 35 };
SDL_Texture* tex{ SDL_CreateTextureFromSurface(ren, img) };
SDL_Event e;
// buffer variables
string Txt; string Tx2; string Tx3; string Tx4; string Tx5; string Tx6; string Tx7;
SDL_Surface* ts1 = nullptr; SDL_Surface* ts2 = nullptr; SDL_Surface* ts3 = nullptr; SDL_Surface* ts4 = nullptr; SDL_Surface* ts5 = nullptr; SDL_Surface* ts6 = nullptr; SDL_Surface* ts7 = nullptr;
SDL_Texture* tb1 = nullptr; SDL_Texture* tb2 = nullptr; SDL_Texture* tb3 = nullptr; SDL_Texture* tb4 = nullptr; SDL_Texture* tb5 = nullptr; SDL_Texture* tb6 = nullptr; SDL_Texture* tb7 = nullptr;
int w{ img->w }; int h{ img->h }; int x{ randomWithinRange(W - w) }; int y{ randomWithinRange(H - h) };
int tbW{ 0 }; int tbH{ 0 }; int X{ 2 }; int tbY{ 1 }; int tb2Y{ 32 }; int tb3Y{ 63 }; int tb4Y{ 94 }; int tb5Y{ 125 }; int tb6Y{ 156 }; int tb7Y{ 187 };
int ms{ 1 };
bool q{ false };
double ANG{ 0 }; int ANGI{ 0 };
// before main loop
// main loop
while (!q)
{
// before buffer setup
SDL_Rect IR{ x, y, w, h };
// buffer setup
ANGI = ANG;
int _TXT_RED = color.r; int _TXT_GRN = color.g; int _TXT_BLU = color.b;
//current x pos, current y pos, current angle, current speed, text color red, text color grn, text color blue,
char buf1[255]; char buf2[255]; char buf3[255]; char buf4[255]; char buf5[255]; char buf6[255]; char buf7[255];
sprintf_s(buf1, "x: %i", x); sprintf_s(buf2, "y: %i", y); sprintf_s(buf3, "a: %i", ANGI); sprintf_s(buf4, "MS: %i", ms); sprintf_s(buf5, "TR: %i", _TXT_RED); sprintf_s(buf6, "TG: %i", _TXT_GRN);
sprintf_s(buf7, "TB: %i", _TXT_BLU);
Txt = buf1; Tx2 = buf2; Tx3 = buf3; Tx4 = buf4; Tx5 = buf5; Tx6 = buf6; Tx7 = buf7;
ts1 = TTF_RenderText_Blended(font, Txt.c_str(), color); ts2 = TTF_RenderText_Blended(font, Tx2.c_str(), color); ts3 = TTF_RenderText_Blended(font, Tx3.c_str(), color);
ts4 = TTF_RenderText_Blended(font, Tx4.c_str(), color); ts5 = TTF_RenderText_Blended(font, Tx5.c_str(), color); ts6 = TTF_RenderText_Blended(font, Tx6.c_str(), color);
ts7 = TTF_RenderText_Blended(font, Tx7.c_str(), color);
tb1 = SDL_CreateTextureFromSurface(ren, ts1); tb2 = SDL_CreateTextureFromSurface(ren, ts2); tb3 = SDL_CreateTextureFromSurface(ren, ts3); tb4 = SDL_CreateTextureFromSurface(ren, ts4);
tb5 = SDL_CreateTextureFromSurface(ren, ts5); tb6 = SDL_CreateTextureFromSurface(ren, ts6); tb7 = SDL_CreateTextureFromSurface(ren, ts7);
SDL_QueryTexture(tb1, NULL, NULL, &tbW, &tbH); SDL_QueryTexture(tb2, NULL, NULL, &tbW, &tbH); SDL_QueryTexture(tb3, NULL, NULL, &tbW, &tbH); SDL_QueryTexture(tb4, NULL, NULL, &tbW, &tbH);
SDL_QueryTexture(tb5, NULL, NULL, &tbW, &tbH); SDL_QueryTexture(tb6, NULL, NULL, &tbW, &tbH); SDL_QueryTexture(tb7, NULL, NULL, &tbW, &tbH);
SDL_Rect Rct{ X, tbY, tbW, tbH }; SDL_Rect Rc2{ X, tb2Y, tbW, tbH }; SDL_Rect Rc3{ X, tb3Y, tbW, tbH }; SDL_Rect Rc4{ X, tb4Y, tbW, tbH }; SDL_Rect Rc5{ X, tb5Y, tbW, tbH }; SDL_Rect Rc6{ X, tb6Y, tbW, tbH };
SDL_Rect Rc7{ X, tb7Y, tbW, tbH };
// set display renders
SDL_SetRenderDrawColor(ren, 0, 0, 0, 255);
SDL_RenderClear(ren);
SDL_RenderCopyEx(ren, tex, NULL, &IR, ANG, 0, SDL_FLIP_NONE);
SDL_RenderCopy(ren, tb1, NULL, &Rct); SDL_RenderCopy(ren, tb2, NULL, &Rc2); SDL_RenderCopy(ren, tb3, NULL, &Rc3); SDL_RenderCopy(ren, tb4, NULL, &Rc4); SDL_RenderCopy(ren, tb5, NULL, &Rc5);
SDL_RenderCopy(ren, tb6, NULL, &Rc6); SDL_RenderCopy(ren, tb7, NULL, &Rc7);
SDL_RenderPresent(ren);
while (SDL_PollEvent(&e))
{
if (e.type == SDL_QUIT) q = true;
else if (e.type == SDL_KEYDOWN)
{
switch (e.key.keysym.sym)
{
case SDLK_w: y -= ms; break; case SDLK_s: y += ms; break;
case SDLK_a: x -= ms; break; case SDLK_d: x += ms; break;
case SDLK_r: if (color.r < 255) color.r += 1; else if (color.r == 255) color.r = 0; break;
case SDLK_g: if (color.g < 255) color.g += 1; else if (color.g == 255) color.g = 0; break;
case SDLK_b: if (color.b < 255) color.b += 1; else if (color.b == 255) color.b = 0; break;
case SDLKCM: ANG -= 1; break;
case SDLKPR: ANG += 1; break;
case SDLKSP: Screenshot(ren, "capture.bmp", W, H); break;
case SDLK_q: if (ms > 1) { ms -= 1; /*std::cout << "ms decreased to " << ms << "\n";*/ } /*else if (ms == 1) std::cout << "ms cannot decrease further\n";*/ break;
case SDLK_e: if (ms < 10) { ms += 1; /*std::cout << "ms increased to " << ms << "\n";*/ } /*else if (ms == 10) ms = 10; std::cout << "ms cannot increase further\n";*/ break;
case SDLKES: q = true; break;
}
}
}
}
// after main loop - usually nothing
// exit code
SDL_DestroyTexture(tb1); SDL_DestroyTexture(tb2); SDL_DestroyTexture(tb3); SDL_DestroyTexture(tb4); SDL_DestroyTexture(tb5); SDL_DestroyTexture(tb6); SDL_DestroyTexture(tb7); SDL_DestroyTexture(tex);
SDL_FreeSurface(ts1); SDL_FreeSurface(ts2); SDL_FreeSurface(ts3); SDL_FreeSurface(ts4); SDL_FreeSurface(ts5); SDL_FreeSurface(ts6); SDL_FreeSurface(ts7); SDL_FreeSurface(img);
TTF_CloseFont(font);
SDL_DestroyRenderer(ren);
SDL_DestroyWindow(win);
TTF_Quit();
IMG_Quit();
SDL_Quit();
return 0;
}
Its because you keep loading more textures and surfaces without freeing them. You only need to load them once. Put your buffer setup before the loop, also check the memory usage when its running im almost certain its gonna be rising alot
my name is budi.
i am a newbie in image processing, recently i've been trying to learn about opencv and visual studio. i already succeed to detect the face then draw the circle around the face that i've detected thanks to the example in some DIY website. my question is, how to detect a circle that encircling the face ? so i can use it for "if" condition, for example
if ( condition )//there is at least one circle in the frame
{
bla bla bla
}
here is the code i use :
#include <opencv2/objdetect/objdetect.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/ocl/ocl.hpp>
#include <opencv2/core/core.hpp>
#include <opencv2/opencv.hpp>
#include <opencv2/opencv_modules.hpp>
#include <opencv2/videostab/deblurring.hpp>
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <Windows.h>
#include <sstream>
#include <string>
using namespace std;
using namespace cv;
const static Scalar colors[] = { CV_RGB(0,0,255),
CV_RGB(0,128,255),
CV_RGB(0,255,255),
CV_RGB(0,255,0),
CV_RGB(255,128,0),
CV_RGB(255,255,0),
CV_RGB(255,0,0),
CV_RGB(255,0,255)
} ;
void Draw(Mat& img, vector<Rect>& faces, double scale);
int main(int argc, const char** argv)
{
// Setup serial port connection and needed variables.
HANDLE hSerial = CreateFile(L"COM8", GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
if (hSerial !=INVALID_HANDLE_VALUE)
{
printf("Port opened! \n");
DCB dcbSerialParams;
GetCommState(hSerial,&dcbSerialParams);
dcbSerialParams.BaudRate = CBR_9600;
dcbSerialParams.ByteSize = 8;
dcbSerialParams.Parity = NOPARITY;
dcbSerialParams.StopBits = ONESTOPBIT;
//CvMemStorage* p_strStorage;
char incomingData[256] = ""; // don't forget to pre-allocate memory
//printf("%s\n",incomingData);
int dataLength = 256;
int readResult = 0;
SetCommState(hSerial, &dcbSerialParams);
}
else
{
if (GetLastError() == ERROR_FILE_NOT_FOUND)
{
printf("Serial port doesn't exist! \n");
}
printf("Error while setting up serial port! \n");
}
char outputChars[] ="c" ;
DWORD btsIO;
//void Draw(Mat& img, vector<Rect>& faces, double scale);
Mat frame, frameCopy, image;
//int i; // loop counter
//char charCheckForEscKey; // char for checking key press (Esc exits program)
//create the cascade classifier object used for the face detection
CascadeClassifier face_cascade;
//use the haarcascade_frontalface_alt.xml library
face_cascade.load("haarcascade_frontalface_alt.xml");
//setup video capture device and link it to the first capture device
VideoCapture captureDevice;
captureDevice.open(0);
if(captureDevice.open(0) == NULL)
{ // if capture was not successful . . .
printf("error: capture error \n"); // error message to standard out . . .
getchar(); // getchar() to pause for user see message . . .
return(-1);
}
//setup image files used in the capture process
Mat captureFrame;
Mat grayscaleFrame;
//create a window to present the results
namedWindow("FaceDetection", 1);
//int servoPosition = 90;
//int servoOrientation = 0;
//int servoPosition1=90;
//int servoOrientation1=0;
//create a loop to capture and find faces
while(true)
{
//p_imgOriginal = captureFrame;
//capture a new image frame
captureDevice>>captureFrame;
//convert captured image to gray scale and equalize
cvtColor(captureFrame, grayscaleFrame, CV_BGR2GRAY);
imshow("Grayscale", grayscaleFrame);
equalizeHist(grayscaleFrame, grayscaleFrame);
//p_strStorage = cvCreateMemStorage(0);
//create a vector array to store the face found
std::vector<Rect> faces;
//find faces and store them in the vector array
face_cascade.detectMultiScale(grayscaleFrame, faces, 1.1, 3, CV_HAAR_FIND_BIGGEST_OBJECT|CV_HAAR_SCALE_IMAGE, Size(30,30));
//draw a circle for all found faces in the vector array on the original image
//for(int i = 0; i < faces.size(); i++)
int i = 0;
//for( int i = 0; i < faces.size(); i++ )
for( vector<Rect>::const_iterator r = faces.begin(); r != faces.end(); r++, i++ )
{
Point center( faces[i].x + faces[i].width*0.5, faces[i].y + faces[i].height*0.5 );
Scalar color = colors[i%8];
center.x = cvRound((r->x + r->width*0.5));
center.y = cvRound((r->y + r->height*0.5));
Point pt1(faces[i].x + faces[i].width, faces[i].y + faces[i].height);
Point pt2(faces[i].x, faces[i].y);
int radius;
int X = faces[i].x;
int Y = faces[i].y;
radius = cvRound((faces[i].width + faces[i].height)*0.25);
//ellipse( frame, center, Size( faces[i].width*0.5, faces[i].height*0.5), 0, 0, 360, Scalar( 255, 0, 255 ), 2, 8, 0 );
//rectangle(captureFrame, pt1, pt2, cvScalar(0, 255, 0, 0), 1, 8, 0);
circle(captureFrame,center,radius,cvScalar(0, 255, 0, 0), 1, 8, 0);
cout << "X:" << faces[i].x << " Y:" << faces[i].y << endl;
if (radius >= 85)
{
outputChars[0] = 'a';
WriteFile(hSerial, outputChars, strlen(outputChars), &btsIO, NULL);
cout << "radius >= 85, advertising begin" << endl;
//FlushFileBuffers(hSerial);
}
else if (radius <= 84)
{
outputChars[0] = 'b';
WriteFile(hSerial, outputChars, strlen(outputChars), &btsIO, NULL);
//cout << "radius >= 85, advertising begin" << endl;
}
/*else if (radius >= 85 | X<=164 && X>=276)
{
outputChars[0] = 'z';
WriteFile(hSerial, outputChars, strlen(outputChars), &btsIO, NULL);
cout << "radius >= 85, advertising begin" << endl;
//FlushFileBuffers(hSerial);
}
else if (radius < 85)
{
outputChars[0] = 'b';
WriteFile(hSerial, outputChars, strlen(outputChars), &btsIO, NULL);
cout << "radius: " << radius << "radius < 85, advertising end!" << endl;
//FlushFileBuffers(hSerial);
}
/*if (X>=165 | X<=275)
{
outputChars[0]='u';
WriteFile(hSerial, outputChars, strlen(outputChars), &btsIO, NULL);
cout <<"Face in the middle of the frame" << endl;
FlushFileBuffers(hSerial);
}
/*if (X<=164 | X>=276)
{
outputChars[0]='y';
WriteFile(hSerial, outputChars, strlen(outputChars), &btsIO, NULL);
cout <<"no face in the middle of the frame" << endl;
//FlushFileBuffers(hSerial);
}*/
}
//print the output
imshow("FaceDetection", captureFrame);
//pause for 200ms
waitKey(60);
}
cvDestroyWindow("FaceDetection");
cvDestroyWindow("Grayscale");
FlushFileBuffers(hSerial);
// This closes the Serial Port
CloseHandle(hSerial);
return 0;
}
please help me, and thank you all for the attention.
I'm moving my OpenGL project over from GLUT to GLFW. Currently I am trying to get text to appear on screen using the library FreeType. I am following the tutorials from their site, but I am stuck. I believe I have it all written out, but for some reason it isn't working. What am I missing?
Here is my code:
#include <iostream>
#include <stdlib.h>
// Include GLEW
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include "ft2build.h"
#include FT_FREETYPE_H
FT_Library library;
FT_Face face;
static void error_callback(int error, const char* description)
{
fputs(description, stderr);
}
//should only be used for key press or key release
static void key_press(GLFWwindow* window, int key, int scancode, int action, int mods)
{
if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS)
glfwSetWindowShouldClose(window, GL_TRUE);
}
void render_text(const std::string &str, FT_Face face, float x, float y, float sx, float sy) {
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
const FT_GlyphSlot glyph = face->glyph;
for (auto c : str) {
if (FT_Load_Char(face, c, FT_LOAD_RENDER) != 0)
continue;
glTexImage2D(GL_TEXTURE_2D, 0, GL_R8,
glyph->bitmap.width, glyph->bitmap.rows,
0, GL_RED, GL_UNSIGNED_BYTE, glyph->bitmap.buffer);
const float vx = x + glyph->bitmap_left * sx;
const float vy = y + glyph->bitmap_top * sy;
const float w = glyph->bitmap.width * sx;
const float h = glyph->bitmap.rows * sy;
struct {
float x, y, s, t;
} data[6] = {
{ vx, vy, 0, 0 },
{ vx, vy - h, 0, 1 },
{ vx + w, vy, 1, 0 },
{ vx + w, vy, 1, 0 },
{ vx, vy - h, 0, 1 },
{ vx + w, vy - h, 1, 1 }
};
glBufferData(GL_ARRAY_BUFFER, 24 * sizeof(float), data, GL_DYNAMIC_DRAW);
glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, 0);
glDrawArrays(GL_TRIANGLES, 0, 6);
x += (glyph->advance.x >> 6) * sx;
y += (glyph->advance.y >> 6) * sy;
}
glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
}
void Resize(GLFWwindow* window)
{
int width, height;
glfwGetFramebufferSize(window, &width, &height);
glViewport(0, 0, width, height);
glClear(GL_COLOR_BUFFER_BIT);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(-5.f, 5.f, -5.f, 5.f, 5.f, -5.f);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
void Setup()
{
glEnable(GL_TEXTURE_2D);
glEnable(GL_DEPTH_TEST); // Depth Testing
glDepthFunc(GL_LEQUAL);
glDisable(GL_CULL_FACE);
glCullFace(GL_BACK);
//used for font
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
}
void Display(GLFWwindow* window)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
render_text("TEST", face, 0, 0, 100, 100);
glfwSwapBuffers(window);
glfwPollEvents();
}
void Update(GLFWwindow* window)
{
Display(window);
}
int main(void)
{
GLFWwindow* window;
glfwSetErrorCallback(error_callback);
if (!glfwInit())
exit(EXIT_FAILURE);
window = glfwCreateWindow(640, 480, "Simple example", NULL, NULL);
if (!window)
{
glfwTerminate();
exit(EXIT_FAILURE);
}
glfwMakeContextCurrent(window);
glfwSwapInterval(1);
glewExperimental = true;
if (glewInit() != GLEW_OK)
{
//Problem: glewInit failed, something is seriously wrong.
std::cout << "glewInit failed, aborting." << std::endl;
exit(EXIT_FAILURE);
}
FT_Error error = FT_Init_FreeType(&library);
if (error) {
fprintf(stderr, "Could not init freetype library\n");
return 1;
}
error = FT_New_Face(library, "Stoke-Regular.ttf", 0, &face);
if (error == FT_Err_Unknown_File_Format)
{
std::cout << "font is unsupported" << std::endl;
return 1;
}
else if (error)
{
std::cout << "font could not be read or opened" << std::endl;
return 1;
}
error = FT_Set_Pixel_Sizes(face, 0, 48);
if (error)
{
std::cout << "Problem adjusting pixel size" << std::endl;
return 1;
}
//keyboard controls
glfwSetKeyCallback(window, key_press);
Resize(window);
Setup();
while (!glfwWindowShouldClose(window))
{
Update(window);
}
glfwDestroyWindow(window);
glfwTerminate();
exit(EXIT_SUCCESS);
}
How to turn on antialiasing in SDL2, when using SDL_RenderCopyEx?
I find some articles that suggest to use:
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1);
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 2);
and
glEnable(GL_MULTISAMPLE);
But this makes no effect. Any ideas?
int Buffers, Samples;
SDL_GL_GetAttribute( SDL_GL_MULTISAMPLEBUFFERS, &Buffers );
SDL_GL_GetAttribute( SDL_GL_MULTISAMPLESAMPLES, &Samples );
cout << "buf = " << Buffers << ", samples = " << Samples;
returns
buf = -858993460, samples = -858993460.
EDIT: CODE:
#include <windows.h>
#include <iostream>
#include <SDL2/include/SDL.h>
#include <SDL2/include/SDL_image.h>
using namespace std;
int main( int argc, char * args[] )
{
// Inicjacja SDL'a
SDL_Init(SDL_INIT_EVERYTHING);
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1);
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 8);
SDL_GL_SetAttribute(SDL_GL_ACCELERATED_VISUAL, 1);
// Tworzenie okna
SDL_Window *win = nullptr;
win = SDL_CreateWindow("abc", 100, 100, 800, 600, SDL_WINDOW_FULLSCREEN | SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN);
if (win == nullptr)
{
std::cout << SDL_GetError() << std::endl;
system("pause");
return 1;
}
int Buffers, Samples;
SDL_GL_GetAttribute( SDL_GL_MULTISAMPLEBUFFERS, &Buffers );
SDL_GL_GetAttribute( SDL_GL_MULTISAMPLESAMPLES, &Samples );
cout << "buf = " << Buffers << ", samples = " << Samples << ".";
// Create Renderer
SDL_Renderer *ren = nullptr;
ren = SDL_CreateRenderer(win, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
if (ren == nullptr)
{
std::cout << SDL_GetError() << std::endl;
return 1;
}
// Create texture
SDL_Texture *tex = nullptr;
tex = IMG_LoadTexture(ren, "circle.png");
SDL_SetTextureAlphaMod(tex, 100);
SDL_Rect s,d;
SDL_Point c;
s.x = s.y = 0;
s.w = s.h = 110;
d.x = 320;
d.y = 240;
d.w = d.h = 110;
c.x = c.y = 55;
// Event Queue
SDL_Event e;
bool quit = false;
int angle = 0;
while(!quit)
{
while (SDL_PollEvent(&e)){
//If user closes he window
if (e.type == SDL_KEYDOWN)
quit = true;
}
angle += 2;
float a = (angle/255.0)/M_PI*180.0;
// Render
SDL_RenderClear(ren);
SDL_RenderCopyEx(ren, tex, &s, &d, a, &c, SDL_FLIP_NONE);
SDL_RenderPresent(ren);
}
// Release
SDL_DestroyTexture(tex);
SDL_DestroyRenderer(ren);
SDL_DestroyWindow(win);
// Quit
SDL_Quit();
return 0;
}
Do not worry about style or errors related to memory deallocation, etc. It was a quick sketch to test the possibility SDL'a
If you're looking for an answer that doesn't require opengl use, then this may be of use:
SDL_SetHint( SDL_HINT_RENDER_SCALE_QUALITY, "1" );
https://wiki.libsdl.org/SDL_HINT_RENDER_SCALE_QUALITY
As far as I can tell by trying it out, the values are not set until the context is created, so if you run your SDL_GL_GetAttribute lines before creating the window you will get un-initialised values back as you are doing at present.
So to get correct values use the SDL_GL_GetAttribute call after creating a context and it should work fine.
Let me know how you get on, and if you need any more help/information I will help as I can.
Addendum:
You look like you have created the window before setting its properties, I have pasted some modified code, which should run fine (apologies, I can't test it until I get access to my home PC).
Rearranged code:
#include <windows.h>
#include <iostream>
#include <SDL2/include/SDL.h>
#include <SDL2/include/SDL_image.h>
#include <gl/include/glew.h>
using namespace std;
void myInit()
{
// SDL Init
SDL_Init(SDL_INIT_EVERYTHING);
// Settings
SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8);
SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8);
SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8);
SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 8);
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 32);
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1);
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 2);
SDL_GL_SetAttribute(SDL_GL_ACCELERATED_VISUAL, 1);
glEnable(GL_MULTISAMPLE);
}
int main( int argc, char * args[] )
{
myInit();
// Window Create
SDL_Window *win = nullptr;
win = SDL_CreateWindow("abc", 100, 100, 800, 600, SDL_WINDOW_SHOWN);
if(win == nullptr) return 1;
// Create Renderer
SDL_Renderer *ren = nullptr;
ren = SDL_CreateRenderer(win, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
if (ren == nullptr) return 1;
int Buffers, Samples;
SDL_GL_GetAttribute( SDL_GL_MULTISAMPLEBUFFERS, &Buffers );
SDL_GL_GetAttribute( SDL_GL_MULTISAMPLESAMPLES, &Samples );
cout << "buf = " << Buffers << ", samples = " << Samples << ".";
// Create texture
SDL_Texture *tex = nullptr;
tex = IMG_LoadTexture(ren, "circle.png");
SDL_SetTextureAlphaMod(tex, 100);
SDL_SetTextureColorMod(tex, 255,0,0);
SDL_Rect s,d;
SDL_Point c;
s.x = s.y = 0;
s.w = s.h = 110;
d.x = 320;
d.y = 240;
d.w = d.h = 220;
c.x = c.y = 110;
// Event Queue
SDL_Event e;
bool quit = false;
int angle = 45.0*M_PI/180;
while(!quit)
{
while (SDL_PollEvent(&e)){
//If user closes the window
if (e.type == SDL_QUIT)
quit = true;
}
// Render
SDL_RenderClear(ren);
SDL_RenderCopyEx(ren, tex, &s, &d, angle, &c, SDL_FLIP_NONE);
SDL_RenderPresent(ren);
}
// Release
SDL_DestroyTexture(tex);
SDL_DestroyRenderer(ren);
SDL_DestroyWindow(win);
// Quit
SDL_Quit();
return 0;
}