#include #include #include #include #define SDL_MAIN_USE_CALLBACKS 1 /* use the callbacks instead of main() */ #include #include #include #include "math/dvc_vector2.h" #include "math/dvc_vector3.h" #include "dvr_triangle.h" #include "dvr_canvas.h" #include "rasterizer/dvc_rasterizer_triangle.h" using namespace davinci; enum MouseAction { MT_NULL, MT_FIRST_LINE, MT_TRIANGLE, MT_PAN, }; const float MIN_SCALE = 4.f; const float MAX_SCALE = 120.f; const float TRIANGLE_BORDER_WIDTH = 1.5f; const float ACTION_WIDTH = 1.f; const fVector3 GRID_BORDER_COLOR = fVector3(0.f, 0.f, 0.f); const fVector3 GRID_CROSS_COLOR = fVector3(0.1f, 0.1f, 0.1f); const fVector3 TRIANGLE_BORDER_COLOR = fVector3(0.f, 0.f, 0.f); const fVector3 ACTION_COLOR = fVector3(1.f, 0.f, 0.f); const int32_t CANVAS_WIDTH = 512; const int32_t CANVAS_HEIGHT = 256; int32_t g_viewWidth = 2048; int32_t g_viewHeight = 1440; float32_t g_scale = MAX_SCALE/2.0f; int32_t g_lbCorner_x = 20; int32_t g_lbCorner_y = 20; int32_t g_nDrawGridLevel = 0; //0:all 1:fine+coarse+tile 2:coarse+tile 3: tile int32_t g_screenMousePosX = 0, g_screenMousePosY = 0; float32_t g_mousePosX, g_mousePosY; bool g_bSnapMode = true; float g_fSnapSize = 0.25f; MouseAction g_currentAction = MT_NULL; bool g_bDrawExtension = false; int32_t g_nStartPanX, g_nStartPanY; int32_t g_nPanX, g_nPanY; Triangle g_currentTriangle(INT_MAX, ACTION_COLOR); TriangleArray g_allTriangles; Canvas g_canvas; AntiAliasingTech g_aaTech = AntiAliasingTech::AA_None; SDL_Window* g_window = NULL; SDL_Renderer* g_renderer = NULL; #define trans_w2s_x(x) ((float32_t)(x) * g_scale + g_lbCorner_x + g_nPanX) #define trans_w2s_y(y) ((float32_t)g_viewHeight - ((float32_t)(y) * g_scale + g_lbCorner_y + g_nPanY)) #define trans_s2w_x(x) ((float32_t)(x - g_lbCorner_x - g_nPanX) / g_scale) #define trans_s2w_y(y) ((float32_t)(g_viewHeight - y - g_lbCorner_y - g_nPanY) / g_scale) void _onFramebufferSize(int32_t w, int32_t h) { g_viewWidth = w; g_viewHeight = h > 0 ? h : 1; if (g_scale < 10.f) g_nDrawGridLevel = 3; else if (g_scale < 20.f) g_nDrawGridLevel = 2; else if (g_scale < 50.f) g_nDrawGridLevel = 1; else g_nDrawGridLevel = 0; } static void _drawGrid(void) { int32_t horLength = (int32_t)floorf(g_viewWidth / g_scale); int32_t verLength = (int32_t)floorf(g_viewHeight / g_scale); // draw canvas background SDL_FRect rect; rect.x = trans_w2s_x(0); rect.y = trans_w2s_y(0); rect.w = g_canvas.width() * g_scale; rect.h = -g_canvas.height() * g_scale; SDL_SetRenderDrawColorFloat(g_renderer, 255, 255, 255, SDL_ALPHA_OPAQUE_FLOAT); SDL_RenderFillRect(g_renderer, &rect); fVector3 lineColor[] = { fVector3(0.f, 0.f, 0.f), fVector3(0.5f, 0.5f, 0.5f), fVector3(0.7f,0.7f,0.7f), fVector3(0.9f, 0.9f,0.9f) }; // Horizontal lines for (int32_t i = (int32_t)trans_s2w_y(0); ; i--) { if (i > g_canvas.height()) continue; if (i < 0) break; float32_t screenY = trans_w2s_y(i); if (screenY < 0) continue; if (screenY > g_viewHeight) break; int32_t level = 3; if (i % 64 == 0)level = 0; else if (i % 16 == 0) level = 1; else if (i % 4 == 0) level = 2; if (level > 3 - g_nDrawGridLevel) continue; SDL_SetRenderDrawColorFloat(g_renderer, lineColor[level].x, lineColor[level].y, lineColor[level].z, SDL_ALPHA_OPAQUE_FLOAT); SDL_RenderLine(g_renderer, trans_w2s_x(0), screenY, trans_w2s_x(g_canvas.width()), screenY); } // Vertical lines for (int32_t j = (int32_t)trans_s2w_x(0); ; j++) { if (j < 0) continue; if (j > g_canvas.width()) break; float32_t screenX = trans_w2s_x(j); if (screenX < 0) continue; if (screenX > g_viewWidth) break; int32_t level = 3; if (j % 64 == 0)level = 0; else if (j % 16 == 0) level = 1; else if (j % 4 == 0) level = 2; if (level > 3 - g_nDrawGridLevel) continue; SDL_SetRenderDrawColorFloat(g_renderer, lineColor[level].x, lineColor[level].y, lineColor[level].z, SDL_ALPHA_OPAQUE_FLOAT); SDL_RenderLine(g_renderer, screenX, trans_w2s_y(0), screenX, trans_w2s_y(g_canvas.height())); } } void _drawTriangleBorder(const Triangle& triangle, const fVector3& color, float lineWidth) { SDL_SetRenderDrawColorFloat(g_renderer, color[0], color[1], color[2], SDL_ALPHA_OPAQUE_FLOAT); SDL_FPoint points[4] = { {trans_w2s_x(triangle.m_p0.x), trans_w2s_y(triangle.m_p0.y)}, {trans_w2s_x(triangle.m_p1.x), trans_w2s_y(triangle.m_p1.y)}, {trans_w2s_x(triangle.m_p2.x), trans_w2s_y(triangle.m_p2.y)}, {trans_w2s_x(triangle.m_p0.x), trans_w2s_y(triangle.m_p0.y)} }; SDL_RenderLines(g_renderer, points, 4); } void _drawCanvasPixel() { SDL_SetRenderDrawBlendMode(g_renderer, SDL_BLENDMODE_BLEND); for (int32_t y = 0; y < g_canvas.height(); y++) { for (int32_t x = 0; x < g_canvas.width(); x++) { const Canvas::Pixel& pixel = g_canvas.pixel(x, y); if (pixel.fragementID < 0) continue; SDL_FRect rect; rect.x = trans_w2s_x(x); rect.y = trans_w2s_y(y); rect.w = g_scale; rect.h = -g_scale; SDL_SetRenderDrawColorFloat(g_renderer, pixel.color.x, pixel.color.y, pixel.color.z, pixel.alpha); SDL_RenderFillRect(g_renderer, &rect); } } } void _drawTriangles(void) { _drawCanvasPixel(); for (const auto& triangle : g_allTriangles) { _drawTriangleBorder(triangle, TRIANGLE_BORDER_COLOR, TRIANGLE_BORDER_WIDTH); } } void _drawSegmentInAABB(const fVector2& p0, const fVector2& p1, float xMin, float xMax, float yMin, float yMax) { float32_t dx = p1.x - p0.x; float32_t dy = p1.y - p0.y; if (std::abs(dx) > std::abs(dy)) { float _ymin = (xMin - p0.x) * dy / dx + p0.y; float _ymax = (xMax - p0.x) * dy / dx + p0.y; if (dx > 0) { SDL_RenderLine(g_renderer, trans_w2s_x(xMin), trans_w2s_y(_ymin), trans_w2s_x(p0.x), trans_w2s_y(p0.y) ); SDL_RenderLine(g_renderer, trans_w2s_x(p1.x), trans_w2s_y(p1.y), trans_w2s_x(xMax), trans_w2s_y(_ymax) ); } else { SDL_RenderLine(g_renderer, trans_w2s_x(xMin), trans_w2s_y(_ymin), trans_w2s_x(p1.x), trans_w2s_y(p1.y)); SDL_RenderLine(g_renderer, trans_w2s_x(p0.x), trans_w2s_y(p0.y), trans_w2s_x(xMax), trans_w2s_y(_ymax)); } } else { float _xmin = (yMin - p0.y) * dx / dy + p0.x; float _xmax = (yMax - p0.y) * dx / dy + p0.x; if (dy > 0) { SDL_RenderLine(g_renderer, trans_w2s_x(_xmin), trans_w2s_y(yMin), trans_w2s_x(p0.x), trans_w2s_y(p0.y)); SDL_RenderLine(g_renderer, trans_w2s_x(p1.x), trans_w2s_y(p1.y), trans_w2s_x(_xmax), trans_w2s_y(yMax)); } else { SDL_RenderLine(g_renderer, trans_w2s_x(_xmin), trans_w2s_y(yMin), trans_w2s_x(p1.x), trans_w2s_y(p1.y)); SDL_RenderLine(g_renderer, trans_w2s_x(p0.x), trans_w2s_y(p0.y), trans_w2s_x(_xmax), trans_w2s_y(yMax)); } } } void _drawAction(void) { if (g_bDrawExtension) { SDL_SetRenderDrawColorFloat(g_renderer, ACTION_COLOR.x/2.f, ACTION_COLOR.y/2.f, ACTION_COLOR.z/2.f, SDL_ALPHA_OPAQUE_FLOAT); _drawSegmentInAABB(g_currentTriangle.m_p0.xy(), g_currentTriangle.m_p1.xy(), 0, (float)g_canvas.width(), 0, (float)g_canvas.height()); _drawSegmentInAABB(g_currentTriangle.m_p1.xy(), g_currentTriangle.m_p2.xy(), 0, (float)g_canvas.width(), 0, (float)g_canvas.height()); _drawSegmentInAABB(g_currentTriangle.m_p2.xy(), g_currentTriangle.m_p0.xy(), 0, (float)g_canvas.width(), 0, (float)g_canvas.height()); } SDL_SetRenderDrawColorFloat(g_renderer, ACTION_COLOR.x, ACTION_COLOR.y, ACTION_COLOR.z, SDL_ALPHA_OPAQUE_FLOAT); switch (g_currentAction) { case MT_FIRST_LINE: { SDL_RenderLine(g_renderer, trans_w2s_x(g_currentTriangle.m_p0.x), trans_w2s_y(g_currentTriangle.m_p0.y), trans_w2s_x(g_currentTriangle.m_p1.x), trans_w2s_y(g_currentTriangle.m_p1.y) ); } break; case MT_TRIANGLE: { _drawTriangleBorder(g_currentTriangle, ACTION_COLOR, ACTION_WIDTH); } break; default: break; } } void _drawPixelSample() { const float crossLength = 0.2f; //sample cross if (g_nDrawGridLevel < 3) { SDL_SetRenderDrawColorFloat(g_renderer, GRID_CROSS_COLOR.x, GRID_CROSS_COLOR.y, GRID_CROSS_COLOR.z, SDL_ALPHA_OPAQUE_FLOAT); for (int32_t i = 0; i < g_canvas.height(); i++) { for (int32_t j = 0; j < g_canvas.width(); j++) { const Canvas::Pixel& pixel = g_canvas.pixel(j, i); if (pixel.fragementID < 0) continue; if (g_aaTech == AntiAliasingTech::AA_None) { SDL_RenderLine(g_renderer, trans_w2s_x(j + 0.5f - crossLength), trans_w2s_y(i + 0.5f - crossLength), trans_w2s_x(j + 0.5f + crossLength), trans_w2s_y(i + 0.5f + crossLength) ); SDL_RenderLine(g_renderer, trans_w2s_x(j + 0.5f - crossLength), trans_w2s_y(i + 0.5f + crossLength), trans_w2s_x(j + 0.5f + crossLength), trans_w2s_y(i + 0.5f - crossLength) ); } else if (g_aaTech == AntiAliasingTech::AA_MSAA_2X2) { for (int32_t ii = 0; ii < 2; ii++) { for (int32_t jj = 0; jj < 2; jj++) { int32_t maskOffset = ii * 2 + jj; if (((pixel.mask >> maskOffset) & 1) == 0U) continue; SDL_RenderLine(g_renderer, trans_w2s_x(j + 0.25f + jj * 0.5f - crossLength / 2), trans_w2s_y(i + 0.25f + ii * 0.5f - crossLength / 2), trans_w2s_x(j + 0.25f + jj * 0.5f + crossLength / 2), trans_w2s_y(i + 0.25f + ii * 0.5f + crossLength / 2) ); SDL_RenderLine(g_renderer, trans_w2s_x(j + 0.25f + jj * 0.5f - crossLength / 2), trans_w2s_y(i + 0.25f + ii * 0.5f + crossLength / 2), trans_w2s_x(j + 0.25f + jj * 0.5f + crossLength / 2), trans_w2s_y(i + 0.25f + ii * 0.5f - crossLength / 2) ); } } } else if (g_aaTech == AntiAliasingTech::AA_MSAA_4X4) { for (int32_t ii = 0; ii < 4; ii++) { for (int32_t jj = 0; jj < 4; jj++) { int32_t maskOffset = ii * 4 + jj; if (((pixel.mask >> maskOffset) & 1) == 0U) continue; SDL_RenderLine(g_renderer, trans_w2s_x(j + 0.125f + jj * 0.25f - crossLength/4), trans_w2s_y(i + 0.125f + ii * 0.25f - crossLength/4), trans_w2s_x(j + 0.125f + jj * 0.25f + crossLength/4), trans_w2s_y(i + 0.125f + ii * 0.25f + crossLength/4) ); SDL_RenderLine(g_renderer, trans_w2s_x(j + 0.125f + jj * 0.25f - crossLength/4), trans_w2s_y(i + 0.125f + ii * 0.25f + crossLength/4), trans_w2s_x(j + 0.125f + jj * 0.25f + crossLength/4), trans_w2s_y(i + 0.125f + ii * 0.25f - crossLength/4) ); } } } } } //for (int32_t i = (int32_t)trans_s2w_y(0); ; i--) //{ // if (i > g_canvas.height()) continue; // if (i < 0) break; //} //float crossLength = 0.2f; //for (int i = 0; i < verLength; i++) //{ // for (int j = 0; j < horLength; j++) // { // SDL_RenderLine(g_renderer, // trans_w2s_x(j + 0.5f - crossLength), trans_w2s_y(i + 0.5f - crossLength), // trans_w2s_x(j + 0.5f + crossLength), trans_w2s_y(i + 0.5f + crossLength) // ); // SDL_RenderLine(g_renderer, // trans_w2s_x(j + 0.5f - crossLength), trans_w2s_y(i + 0.5f + crossLength), // trans_w2s_x(j + 0.5f + crossLength), trans_w2s_y(i + 0.5f - crossLength) // ); // } //} } } void _drawMouseCursor(void) { if (g_bSnapMode && g_currentAction!=MT_PAN) { SDL_SetRenderDrawColorFloat(g_renderer, 0, 0, 0, SDL_ALPHA_OPAQUE_FLOAT); const float32_t CursorLength = 10.f / g_scale; SDL_RenderLine(g_renderer, trans_w2s_x(g_mousePosX - CursorLength), trans_w2s_y(g_mousePosY), trans_w2s_x(g_mousePosX + CursorLength), trans_w2s_y(g_mousePosY) ); SDL_RenderLine(g_renderer, trans_w2s_x(g_mousePosX), trans_w2s_y(g_mousePosY - CursorLength), trans_w2s_x(g_mousePosX), trans_w2s_y(g_mousePosY + CursorLength) ); } } void _drawDebugText() { const float32_t TextHeight = (float32_t)SDL_DEBUG_TEXT_FONT_CHARACTER_SIZE*1.5; SDL_SetRenderDrawColorFloat(g_renderer, 0, 0, 0, SDL_ALPHA_OPAQUE_FLOAT); SDL_SetRenderScale(g_renderer, 1.5f, 1.5f); SDL_RenderDebugText(g_renderer, 20, 20, "Press 'S' to turn on/off snap mode."); SDL_RenderDebugText(g_renderer, 20, 20 + TextHeight, "Click 'LeftMouseButton' to draw new triangle."); SDL_SetRenderScale(g_renderer, 1.0f, 1.0f); } inline float _snapPosition(float pos) { if (g_fSnapSize < 1) { int invSize = (int)(1.f / g_fSnapSize); float x_f = floorf(((pos - floorf(pos)) * invSize + 0.5f)) / (float)invSize; return floorf(pos) + x_f; } else { return floorf(pos - floorf(pos / g_fSnapSize) + 0.5f) * g_fSnapSize; } } void _onMouseMove(float32_t x, float32_t y) { g_screenMousePosX = (int32_t)x; g_screenMousePosY = (int32_t)y; g_mousePosX = trans_s2w_x(x); g_mousePosY = trans_s2w_y(y); if (g_bSnapMode && g_currentAction != MT_PAN) { g_mousePosX = _snapPosition(g_mousePosX); g_mousePosY = _snapPosition(g_mousePosY); } switch (g_currentAction) { case MT_FIRST_LINE: { g_currentTriangle.m_p1 = fVector3(g_mousePosX, g_mousePosY, 0); } break; case MT_TRIANGLE: { g_currentTriangle.m_p2 = fVector3(g_mousePosX, g_mousePosY, 0); g_currentTriangle.build(g_canvas.width(), g_canvas.height(), g_aaTech); g_canvas.update(g_aaTech, g_allTriangles, &g_currentTriangle); } break; case MT_PAN: { g_nPanX = g_screenMousePosX - g_nStartPanX; g_nPanY = -(g_screenMousePosY - g_nStartPanY); } break; default: break; } } void _onMouseWheel(float32_t x, float32_t y) { g_scale += (float)y * g_scale * 0.05f; if (g_scale < MIN_SCALE) g_scale = MIN_SCALE; if (g_scale > MAX_SCALE) g_scale = MAX_SCALE; _onFramebufferSize(g_viewWidth, g_viewHeight); } void _onKeyDown(SDL_Keycode key) { if (SDLK_S == key) { g_bSnapMode = !g_bSnapMode; } else if (SDLK_A == key) { if (g_currentAction == MT_NULL) { if (g_aaTech == AntiAliasingTech::AA_None) { g_aaTech = AntiAliasingTech::AA_MSAA_2X2; } else if (g_aaTech == AntiAliasingTech::AA_MSAA_2X2) { g_aaTech = AntiAliasingTech::AA_MSAA_4X4; } else if (g_aaTech == AntiAliasingTech::AA_MSAA_4X4) { g_aaTech = AntiAliasingTech::AA_None; } for (auto& triangle : g_allTriangles) { triangle.build(g_canvas.width(), g_canvas.height(), g_aaTech); } g_canvas.update(g_aaTech, g_allTriangles); } } else if (SDLK_ESCAPE == key) { g_currentAction = MT_NULL; g_bDrawExtension = false; } } void _onMouseDown(Uint8 button) { if (button == SDL_BUTTON_MIDDLE) { if (g_currentAction == MT_NULL) { g_currentAction = MT_PAN; g_nStartPanX = g_screenMousePosX; g_nStartPanY = g_screenMousePosY; g_nPanX = g_nPanY = 0; } } } void _onMouseUp(Uint8 button) { if (button == SDL_BUTTON_LEFT) { switch (g_currentAction) { case MT_NULL: { g_currentTriangle.m_p0 = g_currentTriangle.m_p1 = fVector3(g_mousePosX, g_mousePosY, 0); g_currentAction = MT_FIRST_LINE; g_bDrawExtension = false; } break; case MT_FIRST_LINE: { g_currentTriangle.m_p1 = g_currentTriangle.m_p2 = fVector3(g_mousePosX, g_mousePosY, 0); g_currentAction = MT_TRIANGLE; g_bDrawExtension = true; } break; case MT_TRIANGLE: { g_currentTriangle.m_p2 = fVector3(g_mousePosX, g_mousePosY, 0); g_currentAction = MT_NULL; //build triangle Triangle newTriangle(Triangle::nextID(), Triangle::randomColor()); newTriangle.m_p0 = g_currentTriangle.m_p0; newTriangle.m_p1 = g_currentTriangle.m_p1; newTriangle.m_p2 = g_currentTriangle.m_p2; newTriangle.build(g_canvas.width(), g_canvas.height(), g_aaTech); g_allTriangles.push_back(std::move(newTriangle)); g_canvas.update(g_aaTech, g_allTriangles); g_bDrawExtension = true; } break; default: break; } } else if (button== SDL_BUTTON_RIGHT) { g_currentAction = MT_NULL; g_bDrawExtension = false; g_canvas.update(g_aaTech, g_allTriangles); } else if (button == SDL_BUTTON_MIDDLE) { if (g_currentAction == MT_PAN) { g_currentAction = MT_NULL; g_lbCorner_x += g_nPanX; g_lbCorner_y += g_nPanY; g_nPanX = g_nPanY = 0; } } } void _buildDemoTriangles(void) { // https://msdn.microsoft.com/en-us/library/windows/desktop/cc627092(v=vs.85).aspx float32_t triangleData[] = { 1, 2,7, 4,5, 2, 5, 2,7, 4,8, 1, 8, 1,7, 4,9.5f, 2.5f, 1, 7,6, 6,2, 4, 5.25f, 6.75f, 6.25f, 7.75,6.25f, 6.75f, 6.5f, 5.5f,7.5f, 7.5f,7.5f, 6.5f, 11.5f, 1.5f,11.5f, 3.5f, 12.5f, 2.5f, 13.5f, 0.5f,13.5f, 2.5f, 15.5f, 2.5f, 13.5f, 0.5f,15.5f, 2.5f, 15.5f, 0.5f, 13.5f, 6.5f,14.5f, 5.5f, 14.5f, 3.5f, 13.5f, 6.5f,15, 8, 14.5f, 5.5f, 9.5f, 0.5f, 10.5f, 0.5f,9.5f, -1.5f, 7.6f, 5.5f,9.75f, 7.25f, 11.6f, 5.5f, 7.6f, 5.5f, 11.6f, 5.5f, 9.5f, 2.6f, }; size_t triangleCounts = sizeof(triangleData) / (6 * sizeof(float)); for (size_t i = 0; i < triangleCounts; i++) { fVector3 p0(triangleData[i * 6 + 0], triangleData[i * 6 + 1], 0.f); fVector3 p1(triangleData[i * 6 + 2], triangleData[i * 6 + 3], 0.f); fVector3 p2(triangleData[i * 6 + 4], triangleData[i * 6 + 5], 0.f); Triangle triangle(Triangle::nextID(), Triangle::randomColor()); triangle.m_p0 = p0; triangle.m_p1 = p1; triangle.m_p2 = p2; triangle.build(g_canvas.width(), g_canvas.height(), g_aaTech); g_allTriangles.emplace_back(triangle); } } SDL_AppResult SDL_AppInit(void** appstate, int argc, char* argv[]) { // Setup SDL SDL_SetAppMetadata("Davinci Rasterization Test Program", "1.0", "com.thecodeway.davinci"); if (!SDL_Init(SDL_INIT_VIDEO | SDL_INIT_GAMEPAD)) { printf("Error: SDL_Init(): %s\n", SDL_GetError()); return SDL_APP_FAILURE; } if (!SDL_CreateWindowAndRenderer("Davinci Rasterization Test Program", g_viewWidth, g_viewHeight, SDL_WINDOW_RESIZABLE, &g_window, &g_renderer)) { SDL_Log("Couldn't create window/renderer: %s", SDL_GetError()); return SDL_APP_FAILURE; } g_canvas.reset(CANVAS_WIDTH, CANVAS_HEIGHT); _onFramebufferSize(g_viewWidth, g_viewHeight); _buildDemoTriangles(); g_canvas.update(g_aaTech, g_allTriangles); return SDL_APP_CONTINUE; /* carry on with the program! */ } /* This function runs when a new event (mouse input, keypresses, etc) occurs. */ SDL_AppResult SDL_AppEvent(void* appstate, SDL_Event* event) { switch (event->type) { case SDL_EVENT_QUIT: return SDL_APP_SUCCESS; break; case SDL_EVENT_WINDOW_RESIZED: { _onFramebufferSize(event->window.data1, event->window.data2); } break; case SDL_EVENT_MOUSE_MOTION: { _onMouseMove(event->motion.x, event->motion.y); } break; case SDL_EVENT_MOUSE_WHEEL: { _onMouseWheel(event->wheel.x, event->wheel.y); } break; case SDL_EVENT_KEY_DOWN: { _onKeyDown(event->key.key); } break; case SDL_EVENT_MOUSE_BUTTON_DOWN: { _onMouseDown(event->button.button); } break; case SDL_EVENT_MOUSE_BUTTON_UP: { _onMouseUp(event->button.button); } break; } return SDL_APP_CONTINUE; } SDL_AppResult SDL_AppIterate(void* appstate) { SDL_FRect rect; SDL_SetRenderDrawColor(g_renderer, 0, 99, 177, SDL_ALPHA_OPAQUE); SDL_RenderClear(g_renderer); _drawGrid(); _drawTriangles(); _drawAction(); _drawPixelSample(); _drawMouseCursor(); _drawDebugText(); SDL_RenderPresent(g_renderer); /* put it all on the screen! */ return SDL_APP_CONTINUE; } /* This function runs once at shutdown. */ void SDL_AppQuit(void* appstate, SDL_AppResult result) { }