graphics_system::graphics_system(core::engine& engine) : engine_{engine}, window_{nullptr, [](SDL_Window*){}}, context_{nullptr}, width_{800}, height_{600}, fullscreen_{false}, clear_color_{glm::vec4{0.4f, 0.6f, 0.9f, 1.f}}, shader_manager_{std::make_unique<graphics::shader_manager>(engine_)}, texture_manager_{std::make_unique<graphics::texture_manager>(engine_)} { SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3); SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3); SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE); SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24); SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS,1); SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES,8); auto window_mask = SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN | (fullscreen_ ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0); name_ = "Behaviour Trees"; window_ = std::unique_ptr<SDL_Window, void(*)(SDL_Window*)>( SDL_CreateWindow(name_.c_str(), SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, width_, height_, window_mask), SDL_DestroyWindow); if (!window_) { throw std::runtime_error{"could not create window"}; } auto width = 0; auto height = 0; SDL_GetWindowSize(window_.get(), &width, &height); width_ = width; height_ = height; try { context_ = SDL_GL_CreateContext(window_.get()); } catch (const std::runtime_error& ex) { throw std::runtime_error{std::string{"could not create opengl context with version 4.3. "} + ex.what()}; } SDL_GL_SetSwapInterval(1); glewExperimental = GL_TRUE; if (glewInit() != GLEW_OK) { throw std::runtime_error("requested opengl 4.3 features are not available"); } utils::log << "OpenGL version " << std::string{reinterpret_cast<const char*>(glGetString(GL_VERSION))} << std::endl; if(GLEW_KHR_debug){ glDebugMessageCallback( +[](GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar* message, const void*) { std::cerr << std::string(message,length) << " (source: " << source << ", type: " <<type<< ", id: " << id <<", severity: " << severity << ")" <<std::endl; }, nullptr); } else{ utils::log(utils::LOG_WARNING) << "no opengL debug log available." << std::endl; } clear_color(clear_color_); }
void test_clear_color() { uint8_t expected_color[3] = {0, 0, 0}; Color color = create_color(0, 1, 2); clear_color(&color); assert(color.r == expected_color[0]); assert(color.g == expected_color[1]); assert(color.b == expected_color[2]); printf("Clear Color Passed\n"); }
/* Display a message on the statusbar, and set disable_cursorpos to * true, so that the message won't be immediately overwritten if * constant cursor position display is on. */ void statusbar(const char *msg, ...) { va_list ap; char *bar, *foo; size_t start_x; bool old_whitespace; va_start(ap, msg); /* Curses mode is turned off. If we use wmove() now, it will muck * up the terminal settings. So we just use vfprintf(). */ if (isendwin()) { vfprintf(stderr, msg, ap); va_end(ap); return; } blank_statusbar(); old_whitespace = ISSET(WHITESPACE_DISPLAY); UNSET(WHITESPACE_DISPLAY); bar = charalloc(mb_cur_max() * (COLS - 3)); vsnprintf(bar, mb_cur_max() * (COLS - 3), msg, ap); va_end(ap); foo = display_string(bar, 0, COLS - 4, false); free(bar); if (old_whitespace) { SET(WHITESPACE_DISPLAY); } start_x = (COLS - strlenpt(foo) - 4) / 2; wmove(bottomwin, 0, start_x); set_color(bottomwin, interface_colors[STATUS_BAR]); waddstr(bottomwin, "[ "); waddstr(bottomwin, foo); free(foo); waddstr(bottomwin, " ]"); clear_color(bottomwin, interface_colors[STATUS_BAR]); wnoutrefresh(bottomwin); reset_cursor(); wnoutrefresh(edit); /* Leave the cursor at its position in the edit window, not in * the statusbar. */ disable_cursorpos = true; /* If we're doing quick statusbar blanking, and constant cursor * position display is off, blank the statusbar after only one * keystroke. Otherwise, blank it after twenty-six keystrokes, as * Pico does. */ statusblank = ISSET(QUICK_BLANK) && !ISSET(CONST_UPDATE) ? 1 : 26; }
void test_set_color() { Color expected_color = create_color(255, 255, 255); Color color = create_color(0, 1, 2); clear_color(&color); set_color(&color, &expected_color); assert(color.r == expected_color.r); assert(color.g == expected_color.g); assert(color.b == expected_color.b); printf("Set Color Passed\n"); }
void test_set_rgb_color() { uint8_t expected_color[3] = {255, 255, 255}; Color color = create_color(0, 1, 2); clear_color(&color); set_color_rgb(&color, 255, 255, 255); assert(color.r == expected_color[0]); assert(color.g == expected_color[1]); assert(color.b == expected_color[2]); printf("Set RGB Color Passed\n"); }
/* Write a shortcut key to the help area at the bottom of the window. * keystroke is e.g. "^G" and desc is e.g. "Get Help". We are careful * to write at most len characters, even if len is very small and * keystroke and desc are long. Note that waddnstr(,,(size_t)-1) adds * the whole string! We do not bother padding the entry with blanks. */ void onekey(const std::string& keystroke, const std::string& desc, size_t len) { size_t keystroke_len = keystroke.length() + 1; set_color(bottomwin, interface_colors[KEY_COMBO]); waddnstr(bottomwin, keystroke.c_str(), actual_x(keystroke.c_str(), len)); clear_color(bottomwin, interface_colors[KEY_COMBO]); if (len > keystroke_len) { len -= keystroke_len; } else { len = 0; } if (len > 0) { waddch(bottomwin, ' '); waddnstr(bottomwin, desc.c_str(), actual_x(desc.c_str(), len)); } }
void render_process::process(const render_state_ptr& state) { state_ = state; switch (state_->cmd_) { case cmd_draw: case cmd_draw_index: { draw(); break; } case cmd_clear_color: { clear_color(); break; } default: { assert(0); break; } } }
/* edit_draw() takes care of the job of actually painting a line into * the edit window. fileptr is the line to be painted, at row line of * the window. converted is the actual string to be written to the * window, with tabs and control characters replaced by strings of * regular characters. start is the column number of the first * character of this page. That is, the first character of converted * corresponds to character number actual_x(fileptr->data, start) of the * line. */ void edit_draw(filestruct *fileptr, const char *converted, int line, size_t start) { size_t startpos = actual_x(fileptr->data, start); /* The position in fileptr->data of the leftmost character * that displays at least partially on the window. */ size_t endpos = actual_x(fileptr->data, start + COLS - 1) + 1; /* The position in fileptr->data of the first character that is * completely off the window to the right. * * Note that endpos might be beyond the null terminator of the * string. */ assert(openfile != openfiles.end() && fileptr != NULL && converted != NULL); assert(strlenpt(converted) <= COLS); /* Just paint the string in any case (we'll add color or reverse on * just the text that needs it). */ mvwaddstr(edit, line, 0, converted); /* Tell ncurses to really redraw the line without trying to optimize * for what it thinks is already there, because it gets it wrong in * the case of a wide character in column zero. */ #ifndef USE_SLANG wredrawln(edit, line, 1); #endif /* If color syntaxes are available and turned on, we need to display * them. */ if (!openfile->colorstrings.empty() && !ISSET(NO_COLOR_SYNTAX)) { /* Set up multi-line color data for this line if it's not yet calculated */ if (fileptr->multidata.empty() && openfile->syntax && openfile->syntax->nmultis > 0) { fileptr->multidata.resize(openfile->syntax->nmultis, -1); // assume that '-1' applies until we know otherwise } for (auto tmpcolor : openfile->colorstrings) { int x_start; /* Starting column for mvwaddnstr. Zero-based. */ int paintlen = 0; /* Number of chars to paint on this line. There are * COLS characters on a whole line. */ size_t index; /* Index in converted where we paint. */ regmatch_t startmatch; /* Match position for start_regex. */ regmatch_t endmatch; /* Match position for end_regex. */ if (tmpcolor->bright) { wattron(edit, A_BOLD); } if (tmpcolor->underline) { wattron(edit, A_UNDERLINE); } wattron(edit, COLOR_PAIR(tmpcolor->pairnum)); /* Two notes about regexec(). A return value of zero means * that there is a match. Also, rm_eo is the first * non-matching character after the match. */ /* First case,tmpcolor is a single-line expression. */ if (tmpcolor->end == NULL) { size_t k = 0; /* We increment k by rm_eo, to move past the end of the * last match. Even though two matches may overlap, we * want to ignore them, so that we can highlight e.g. C * strings correctly. */ while (k < endpos) { /* Note the fifth parameter to regexec(). It says * not to match the beginning-of-line character * unless k is zero. If regexec() returns * REG_NOMATCH, there are no more matches in the * line. */ if (regexec(tmpcolor->start, &fileptr->data[k], 1, &startmatch, (k == 0) ? 0 : REG_NOTBOL) == REG_NOMATCH) { break; } /* Translate the match to the beginning of the * line. */ startmatch.rm_so += k; startmatch.rm_eo += k; /* Skip over a zero-length regex match. */ if (startmatch.rm_so == startmatch.rm_eo) { startmatch.rm_eo++; } else if (startmatch.rm_so < endpos && startmatch.rm_eo > startpos) { x_start = (startmatch.rm_so <= startpos) ? 0 : strnlenpt(fileptr->data, startmatch.rm_so) - start; index = actual_x(converted, x_start); paintlen = actual_x(converted + index, strnlenpt(fileptr->data, startmatch.rm_eo) - start - x_start); assert(0 <= x_start && 0 <= paintlen); mvwaddnstr(edit, line, x_start, converted + index, paintlen); } k = startmatch.rm_eo; } } else if (!fileptr->multidata.empty() && fileptr->multidata[tmpcolor->id] != CNONE) { /* This is a multi-line regex. There are two steps. * First, we have to see if the beginning of the line is * colored by a start on an earlier line, and an end on * this line or later. * * We find the first line before fileptr matching the * start. If every match on that line is followed by an * end, then go to step two. Otherwise, find the next * line after start_line matching the end. If that line * is not before fileptr, then paint the beginning of * this line. */ const filestruct *start_line = fileptr->prev; /* The first line before fileptr matching start. */ regoff_t start_col; /* Where it starts in that line. */ const filestruct *end_line; short md = fileptr->multidata[tmpcolor->id]; if (md == -1) { fileptr->multidata[tmpcolor->id] = CNONE; /* until we find out otherwise */ } else if (md == CNONE) { unset_formatting(tmpcolor); continue; } else if (md == CWHOLELINE) { mvwaddnstr(edit, line, 0, converted, -1); unset_formatting(tmpcolor); continue; } else if (md == CBEGINBEFORE) { regexec(tmpcolor->end, fileptr->data, 1, &endmatch, 0); paintlen = actual_x(converted, strnlenpt(fileptr->data, endmatch.rm_eo) - start); mvwaddnstr(edit, line, 0, converted, paintlen); unset_formatting(tmpcolor); continue; } while (start_line != NULL && regexec(tmpcolor->start, start_line->data, 1, &startmatch, 0) == REG_NOMATCH) { /* If there is an end on this line, there is no need * to look for starts on earlier lines. */ if (regexec(tmpcolor->end, start_line->data, 0, NULL, 0) == 0) { goto step_two; } start_line = start_line->prev; } /* If the found start has been qualified as an end earlier, believe it and skip to the next step. */ if (start_line != NULL && !start_line->multidata.empty() && start_line->multidata[tmpcolor->id] == CBEGINBEFORE) { goto step_two; } /* Skip over a zero-length regex match. */ if (startmatch.rm_so == startmatch.rm_eo) { startmatch.rm_eo++; } else { /* No start found, so skip to the next step. */ if (start_line == NULL) { goto step_two; } /* Now start_line is the first line before fileptr * containing a start match. Is there a start on * this line not followed by an end on this line? */ start_col = 0; while (true) { start_col += startmatch.rm_so; startmatch.rm_eo -= startmatch.rm_so; if (regexec(tmpcolor->end, start_line->data + start_col + startmatch.rm_eo, 0, NULL, (start_col + startmatch.rm_eo == 0) ? 0 : REG_NOTBOL) == REG_NOMATCH) { /* No end found after this start. */ break; } start_col++; if (regexec(tmpcolor->start, start_line->data + start_col, 1, &startmatch, REG_NOTBOL) == REG_NOMATCH) { /* No later start on this line. */ goto step_two; } } /* Indeed, there is a start not followed on this * line by an end. */ /* We have already checked that there is no end * before fileptr and after the start. Is there an * end after the start at all? We don't paint * unterminated starts. */ end_line = fileptr; while (end_line != NULL && regexec(tmpcolor->end, end_line->data, 1, &endmatch, 0) == REG_NOMATCH) { end_line = end_line->next; } /* No end found, or it is too early. */ if (end_line == NULL || (end_line == fileptr && endmatch.rm_eo <= startpos)) { goto step_two; } /* Now paint the start of fileptr. If the start of * fileptr is on a different line from the end, * paintlen is -1, meaning that everything on the * line gets painted. Otherwise, paintlen is the * expanded location of the end of the match minus * the expanded location of the beginning of the * page. */ if (end_line != fileptr) { paintlen = -1; fileptr->multidata[tmpcolor->id] = CWHOLELINE; } else { paintlen = actual_x(converted, strnlenpt(fileptr->data, endmatch.rm_eo) - start); fileptr->multidata[tmpcolor->id] = CBEGINBEFORE; } mvwaddnstr(edit, line, 0, converted, paintlen); /* If the whole line has been painted, don't bother looking for any more starts. */ if (paintlen < 0) { continue; } step_two: /* Second step, we look for starts on this line. */ start_col = 0; while (start_col < endpos) { if (regexec(tmpcolor->start, fileptr->data + start_col, 1, &startmatch, (start_col == 0) ? 0 : REG_NOTBOL) == REG_NOMATCH || start_col + startmatch.rm_so >= endpos) { /* No more starts on this line. */ break; } /* Translate the match to be relative to the * beginning of the line. */ startmatch.rm_so += start_col; startmatch.rm_eo += start_col; x_start = (startmatch.rm_so <= startpos) ? 0 : strnlenpt(fileptr->data, startmatch.rm_so) - start; index = actual_x(converted, x_start); if (regexec(tmpcolor->end, fileptr->data + startmatch.rm_eo, 1, &endmatch, (startmatch.rm_eo == 0) ? 0 : REG_NOTBOL) == 0) { /* Translate the end match to be relative to the beginning of the line. */ endmatch.rm_so += startmatch.rm_eo; endmatch.rm_eo += startmatch.rm_eo; /* There is an end on this line. But does * it appear on this page, and is the match * more than zero characters long? */ if (endmatch.rm_eo > startpos && endmatch.rm_eo > startmatch.rm_so) { paintlen = actual_x(converted + index, strnlenpt(fileptr->data, endmatch.rm_eo) - start - x_start); assert(0 <= x_start && x_start < COLS); mvwaddnstr(edit, line, x_start, converted + index, paintlen); if (paintlen > 0) { fileptr->multidata[tmpcolor->id] = CSTARTENDHERE; } } } else { /* There is no end on this line. But we * haven't yet looked for one on later * lines. */ end_line = fileptr->next; while (end_line != NULL && regexec(tmpcolor->end, end_line->data, 0, NULL, 0) == REG_NOMATCH) { end_line = end_line->next; } if (end_line != NULL) { assert(0 <= x_start && x_start < COLS); mvwaddnstr(edit, line, x_start, converted + index, -1); /* We painted to the end of the line, so * don't bother checking any more * starts. */ fileptr->multidata[tmpcolor->id] = CENDAFTER; break; } } start_col = startmatch.rm_so + 1; } } } unset_formatting(tmpcolor); } } /* If the mark is on, we need to display it. */ if (openfile->mark_set && (fileptr->lineno <= openfile->mark_begin->lineno || fileptr->lineno <= openfile->current->lineno) && (fileptr->lineno >= openfile->mark_begin->lineno || fileptr->lineno >= openfile->current->lineno)) { /* fileptr is at least partially selected. */ const filestruct *top; /* Either current or mark_begin, whichever is first. */ size_t top_x; /* current_x or mark_begin_x, corresponding to top. */ const filestruct *bot; size_t bot_x; int x_start; /* Starting column for mvwaddnstr(). Zero-based. */ int paintlen; /* Number of characters to paint on this line. There are * COLS characters on a whole line. */ size_t index; /* Index in converted where we paint. */ mark_order(&top, &top_x, &bot, &bot_x, NULL); if (top->lineno < fileptr->lineno || top_x < startpos) { top_x = startpos; } if (bot->lineno > fileptr->lineno || bot_x > endpos) { bot_x = endpos; } /* The selected bit of fileptr is on this page. */ if (top_x < endpos && bot_x > startpos) { assert(startpos <= top_x); /* x_start is the expanded location of the beginning of the * mark minus the beginning of the page. */ x_start = strnlenpt(fileptr->data, top_x) - start; /* If the end of the mark is off the page, paintlen is -1, * meaning that everything on the line gets painted. * Otherwise, paintlen is the expanded location of the end * of the mark minus the expanded location of the beginning * of the mark. */ if (bot_x >= endpos) { paintlen = -1; } else paintlen = strnlenpt(fileptr->data, bot_x) - (x_start + start); /* If x_start is before the beginning of the page, shift * paintlen x_start characters to compensate, and put * x_start at the beginning of the page. */ if (x_start < 0) { paintlen += x_start; x_start = 0; } assert(x_start >= 0 && x_start <= strlen(converted)); index = actual_x(converted, x_start); if (paintlen > 0) { paintlen = actual_x(converted + index, paintlen); } set_color(edit, interface_colors[FUNCTION_TAG]); mvwaddnstr(edit, line, x_start, converted + index, paintlen); clear_color(edit, interface_colors[FUNCTION_TAG]); } } }
void titlebar(const char *path) { int space = COLS; /* The space we have available for display. */ size_t verlen = strlenpt(PACKAGE_STRING) + 1; /* The length of the version message in columns, plus one for * padding. */ const char *prefix; /* "DIR:", "File:", or "New Buffer". Goes before filename. */ size_t prefixlen; /* The length of the prefix in columns, plus one for padding. */ const char *state; /* "Modified", "View", or "". Shows the state of this * buffer. */ ssize_t statelen = 0; /* The length of the state in columns, or the length of * "Modified" if the state is blank and we're not in the file * browser. */ char *exppath = NULL; /* The filename, expanded for display. */ bool newfie = false; /* Do we say "New Buffer"? */ bool dots = false; /* Do we put an ellipsis before the path? */ set_color(topwin, interface_colors[TITLE_BAR]); blank_titlebar(); /* space has to be at least 4: two spaces before the version message, * at least one character of the version message, and one space * after the version message. */ if (space < 4) { space = 0; } else { /* Limit verlen to 1/3 the length of the screen in columns, * minus three columns for spaces. */ if (verlen > (COLS / 3) - 3) { verlen = (COLS / 3) - 3; } } if (space >= 4) { /* Add a space after the version message, and account for both * it and the two spaces before it. */ mvwaddnstr(topwin, 0, 2, PACKAGE_STRING, actual_x(PACKAGE_STRING, verlen)); verlen += 3; /* Account for the full length of the version message. */ space -= verlen; } /* Don't display the state if we're in the file browser. */ if (path != NULL) { state = ""; } else { state = openfile->modified ? _("Modified") : ISSET(VIEW_MODE) ? _("View") : ""; } statelen = strlenpt((*state == '\0' && path == NULL) ? _("Modified") : state); /* If possible, add a space before state. */ if (space > 0 && statelen < space) { statelen++; } else { goto the_end; } /* path should be a directory if we're in the file browser. */ if (path != NULL) { prefix = _("DIR:"); } else { if (openfile->filename[0] == '\0') { prefix = _("New Buffer"); newfie = true; } else { prefix = _("File:"); } } prefixlen = strnlenpt(prefix, space - statelen) + 1; /* If newfie is false, add a space after prefix. */ if (!newfie && prefixlen + statelen < space) { prefixlen++; } /* If we're not in the file browser, set path to the current * filename. */ if (path == NULL) { path = openfile->filename.c_str(); } /* Account for the full lengths of the prefix and the state. */ if (space >= prefixlen + statelen) { space -= prefixlen + statelen; } else { space = 0; } /* space is now the room we have for the filename. */ if (!newfie) { size_t lenpt = strlenpt(path), start_col; /* Don't set dots to true if we have fewer than eight columns * (i.e. one column for padding, plus seven columns for a * filename). */ dots = (space >= 8 && lenpt >= space); if (dots) { start_col = lenpt - space + 3; space -= 3; } else { start_col = 0; } exppath = display_string(path, start_col, space, false); } /* If dots is true, we will display something like "File: * ...ename". */ if (dots) { mvwaddnstr(topwin, 0, verlen - 1, prefix, actual_x(prefix, prefixlen)); if (space <= -3 || newfie) { goto the_end; } waddch(topwin, ' '); waddnstr(topwin, "...", space + 3); if (space <= 0) { goto the_end; } waddstr(topwin, exppath); } else { size_t exppathlen = newfie ? 0 : strlenpt(exppath); /* The length of the expanded filename. */ /* There is room for the whole filename, so we center it. */ mvwaddnstr(topwin, 0, verlen + ((space - exppathlen) / 3), prefix, actual_x(prefix, prefixlen)); if (!newfie) { waddch(topwin, ' '); waddstr(topwin, exppath); } } the_end: free(exppath); if (state[0] != '\0') { if (statelen >= COLS - 1) { mvwaddnstr(topwin, 0, 0, state, actual_x(state, COLS)); } else { assert(COLS - statelen - 1 >= 0); mvwaddnstr(topwin, 0, COLS - statelen - 1, state, actual_x(state, statelen)); } } clear_color(topwin, interface_colors[TITLE_BAR]); wnoutrefresh(topwin); reset_cursor(); wnoutrefresh(edit); }