Вопрос:
(Я использую SDL2)
SDL – это относительно небольшая библиотека для “низкоуровневого доступа к аудио, клавиатуре, мышке, джойстику и графическому оборудованию через OpenGL и Direct3D”. Она используется для разработки игр и, в моем случае, в качестве простого аудиовизуального вывода и ввода мыши и клавиатуры. Это не “инструментарий”, такой как GTK, Qt, wxWindows и т.д. Но он кроссплатформенный.
Но единственный способ найти форму для рисования – это функции line, rect и pixel.
Помимо использования триггера или “уравнения круга”, как я могу нарисовать кривую? Как насчет общей векторной графики?
Является ли SDL подходящей отправной точкой или я должен искать в другом месте?
Лучший ответ:
Если вы хотите написать свою собственную функцию рисования круга, я бы предложил адаптировать алгоритм SDL2_gfx. У него есть еще много функций, которые уже были реализованы для вас.
Ответ №1
Это пример алгоритма окружности средней точки, как указано выше. Это не требует математической библиотеки и очень быстро. (Рендерится примерно за 500 микросекунд). Это то, что Windows использует/использует для растеризации кругов.
void DrawCircle(SDL_Renderer * renderer, int32_t centreX, int32_t centreY, int32_t radius) { const int32_t diameter = (radius * 2); int32_t x = (radius — 1); int32_t y = 0; int32_t tx = 1; int32_t ty = 1; int32_t error = (tx — diameter); while (x >= y) { // Each of the following renders an octant of the circle SDL_RenderDrawPoint(renderer, centreX + x, centreY — y); SDL_RenderDrawPoint(renderer, centreX + x, centreY + y); SDL_RenderDrawPoint(renderer, centreX — x, centreY — y); SDL_RenderDrawPoint(renderer, centreX — x, centreY + y); SDL_RenderDrawPoint(renderer, centreX + y, centreY — x); SDL_RenderDrawPoint(renderer, centreX + y, centreY + x); SDL_RenderDrawPoint(renderer, centreX — y, centreY — x); SDL_RenderDrawPoint(renderer, centreX — y, centreY + x); if (error <= 0) { ++y; error += ty; ty += 2; } if (error > 0) { —x; tx += 2; error += (tx — diameter); } } } Ответ №2
SDL позволяет сторонним библиотекам рисовать текстуру. Если бы был желателен каир, его можно было бы использовать в такой функции:
cairo_t*cb(cairo_t*cr) {cairo_set_source_rgb(cr, 1.0, 1.0, 1.0); cairo_rectangle(cr, 10, 20, 128, 128); cairo_stroke(cr); return cr; }
то cb можно передать этой функции:
cairo_t*cai(SDL_Window*w,SDL_Renderer*r,cairo_t*(*f)(cairo_t*)) {int width, height, pitch;void *pixels; SDL_GetWindowSize(w, &width, &height); SDL_Texture*t=SDL_CreateTexture(r,SDL_PIXELFORMAT_ARGB8888,SDL_TEXTUREACCESS_STREAMING,width,height); SDL_LockTexture(t, NULL, &pixels, &pitch); cairo_surface_t *cs=cairo_image_surface_create_for_data(pixels,CAIRO_FORMAT_ARGB32,width,height,pitch); cairo_t*s=cairo_create(cs); cairo_t*fr=f(s);SDL_UnlockTexture(t);SDL_RenderCopy(r,t,NULL,NULL);SDL_RenderPresent(r); return fr; } Ответ №3
Если вы хотите сделать круг или эллипс без сторонних библиотек, включите math.h и используйте приведенную ниже функцию. Он очень хорошо рисует эллипс или круги. Протестировано на SDL 2.0.2 и работает. Он рисует одну квадрантную дугу и отображает другие дуги, уменьшая вызовы на cosf и sinf.
//draw one quadrant arc, and mirror the other 4 quadrants void sdl_ellipse(SDL_Renderer* r, int x0, int y0, int radiusX, int radiusY) { float pi = 3.14159265358979323846264338327950288419716939937510; float pih = pi / 2.0; //half of pi //drew 28 lines with 4×4 circle with precision of 150 0ms //drew 132 lines with 25×14 circle with precision of 150 0ms //drew 152 lines with 100×50 circle with precision of 150 3ms const int prec = 27; // precision value; value of 1 will draw a diamond, 27 makes pretty smooth circles. float theta = 0; // angle that will be increased each loop //starting point int x = (float)radiusX * cos(theta);//start point int y = (float)radiusY * sin(theta);//start point int x1 = x; int y1 = y; //repeat until theta >= 90; float step = pih/(float)prec; // amount to add to theta each time (degrees) for(theta=step; theta <= pih; theta+=step)//step through only a 90 arc (1 quadrant) { //get new point location x1 = (float)radiusX * cosf(theta) + 0.5; //new point (+.5 is a quick rounding method) y1 = (float)radiusY * sinf(theta) + 0.5; //new point (+.5 is a quick rounding method) //draw line from previous point to new point, ONLY if point incremented if( (x != x1) || (y != y1) )//only draw if coordinate changed { SDL_RenderDrawLine(r, x0 + x, y0 — y, x0 + x1, y0 — y1 );//quadrant TR SDL_RenderDrawLine(r, x0 — x, y0 — y, x0 — x1, y0 — y1 );//quadrant TL SDL_RenderDrawLine(r, x0 — x, y0 + y, x0 — x1, y0 + y1 );//quadrant BL SDL_RenderDrawLine(r, x0 + x, y0 + y, x0 + x1, y0 + y1 );//quadrant BR } //save previous points x = x1;//save new previous point y = y1;//save new previous point } //arc did not finish because of rounding, so finish the arc if(x!=0) { x=0; SDL_RenderDrawLine(r, x0 + x, y0 — y, x0 + x1, y0 — y1 );//quadrant TR SDL_RenderDrawLine(r, x0 — x, y0 — y, x0 — x1, y0 — y1 );//quadrant TL SDL_RenderDrawLine(r, x0 — x, y0 + y, x0 — x1, y0 + y1 );//quadrant BL SDL_RenderDrawLine(r, x0 + x, y0 + y, x0 + x1, y0 + y1 );//quadrant BR } }