#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" using namespace davinci; enum MouseAction { MT_NULL, MT_FIRST_LINE, MT_TRIANGLE }; const float MIN_SCALE = 4.f; const float MAX_SCALE = 60.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.8f, 0.8f, 0.8f); const fVector3 TRIANGLE_BORDER_COLOR = fVector3(0.f, 0.f, 0.f); const fVector3 ACTION_COLOR = fVector3(1.f, 0.f, 0.f); int32_t g_viewWidth = 2048; int32_t g_viewHeight = 1440; int32_t g_canvasWidth; int32_t g_canvasHeight; float32_t g_scale = MAX_SCALE; 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 float32_t g_mousePosX, g_mousePosY; bool g_bSnapMode = true; float g_fSnapSize = 0.25f; MouseAction g_currentAction = MT_NULL; bool g_bDrawExtension = false; Triangle g_currentTriangle; TriangleVector g_allTriangles; SDL_Window* g_window = NULL; SDL_Renderer* g_renderer = NULL; #define trans_x(x) ((float32_t)(x) * g_scale + g_lbCorner_x) #define trans_y(y) ((float32_t)(y) * g_scale + g_lbCorner_y) void _onFramebufferSize(int32_t w, int32_t h) { g_viewWidth = w; g_viewHeight = h > 0 ? h : 1; g_canvasWidth = ((int32_t)floorf(g_viewWidth / (g_scale * 64)) + 1) * 64; g_canvasHeight = ((int32_t)floorf(g_viewHeight / (g_scale * 64)) + 1) * 64; 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); 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 (int i = 0; i <= verLength; i++) { int 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_x(0), trans_y(i), trans_x(horLength), trans_y(i)); } // Vertical lines for (int j = 0; j <= horLength; j++) { int 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, trans_x(j), trans_y(0), trans_x(j), trans_y(verLength)); } //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); float crossLength = 0.2f; for (int i = 0; i < verLength; i++) { for (int j = 0; j < horLength; j++) { SDL_RenderLine(g_renderer, trans_x(j + 0.5f - crossLength), trans_y(i + 0.5f - crossLength), trans_x(j + 0.5f + crossLength), trans_y(i + 0.5f + crossLength) ); SDL_RenderLine(g_renderer, trans_x(j + 0.5f - crossLength), trans_y(i + 0.5f + crossLength), trans_x(j + 0.5f + crossLength), trans_y(i + 0.5f - crossLength) ); } } } } static void _drawTrianglePixel(const Triangle& triangle) { SDL_SetRenderDrawBlendMode(g_renderer, SDL_BLENDMODE_BLEND); SDL_SetRenderDrawColorFloat(g_renderer, triangle.pixelColor[0], triangle.pixelColor[1], triangle.pixelColor[2], 0.5f); for (const auto& dot : triangle.pixels) { SDL_FRect rect; rect.x = trans_x(dot.first); rect.y = trans_y(dot.second); rect.w = g_scale; rect.h = g_scale; SDL_RenderFillRect(g_renderer, &rect); } } 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_x(triangle.p0.x), trans_y(triangle.p0.y)}, {trans_x(triangle.p1.x), trans_y(triangle.p1.y)}, {trans_x(triangle.p2.x), trans_y(triangle.p2.y)}, {trans_x(triangle.p0.x), trans_y(triangle.p0.y)} }; SDL_RenderLines(g_renderer, points, 4); } void _drawTriangles(void) { for (const auto& triangle : g_allTriangles) { _drawTrianglePixel(triangle); } 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_x(xMin), trans_y(_ymin), trans_x(p0.x), trans_y(p0.y) ); SDL_RenderLine(g_renderer, trans_x(p1.x), trans_y(p1.y), trans_x(xMax), trans_y(_ymax) ); } else { SDL_RenderLine(g_renderer, trans_x(xMin), trans_y(_ymin), trans_x(p1.x), trans_y(p1.y)); SDL_RenderLine(g_renderer, trans_x(p0.x), trans_y(p0.y), trans_x(xMax), trans_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_x(_xmin), trans_y(yMin), trans_x(p0.x), trans_y(p0.y)); SDL_RenderLine(g_renderer, trans_x(p1.x), trans_y(p1.y), trans_x(_xmax), trans_y(yMax)); } else { SDL_RenderLine(g_renderer, trans_x(_xmin), trans_y(yMin), trans_x(p1.x), trans_y(p1.y)); SDL_RenderLine(g_renderer, trans_x(p0.x), trans_y(p0.y), trans_x(_xmax), trans_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.p0.xy(), g_currentTriangle.p1.xy(), 0, (float)g_canvasWidth, 0, (float)g_canvasHeight); _drawSegmentInAABB(g_currentTriangle.p1.xy(), g_currentTriangle.p2.xy(), 0, (float)g_canvasWidth, 0, (float)g_canvasHeight); _drawSegmentInAABB(g_currentTriangle.p2.xy(), g_currentTriangle.p0.xy(), 0, (float)g_canvasWidth, 0, (float)g_canvasHeight); } 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_x(g_currentTriangle.p0.x), trans_y(g_currentTriangle.p0.y), trans_x(g_currentTriangle.p1.x), trans_y(g_currentTriangle.p1.y) ); } break; case MT_TRIANGLE: { g_currentTriangle.build(ACTION_COLOR, g_canvasWidth, g_canvasHeight); _drawTrianglePixel(g_currentTriangle); _drawTriangleBorder(g_currentTriangle, ACTION_COLOR, ACTION_WIDTH); } break; default: break; } } void _drawMouseCursor(void) { if (g_bSnapMode) { SDL_SetRenderDrawColorFloat(g_renderer, 0, 0, 0, SDL_ALPHA_OPAQUE_FLOAT); const float32_t CursorLength = 10.f / g_scale; SDL_RenderLine(g_renderer, trans_x(g_mousePosX - CursorLength), trans_y(g_mousePosY), trans_x(g_mousePosX + CursorLength), trans_y(g_mousePosY) ); SDL_RenderLine(g_renderer, trans_x(g_mousePosX), trans_y(g_mousePosY - CursorLength), trans_x(g_mousePosX), trans_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, g_lbCorner_x, g_lbCorner_y, "Press 'S' to turn on/off snap mode."); SDL_RenderDebugText(g_renderer, g_lbCorner_x, g_lbCorner_y+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_mousePosX = (float)(x - g_lbCorner_x) / g_scale; g_mousePosY = (float)(y - g_lbCorner_y) / g_scale; if (g_bSnapMode) { g_mousePosX = _snapPosition(g_mousePosX); g_mousePosY = _snapPosition(g_mousePosY); } switch (g_currentAction) { case MT_FIRST_LINE: { g_currentTriangle.p1 = fVector3(g_mousePosX, g_mousePosY, 0); } break; case MT_TRIANGLE: { g_currentTriangle.p2 = fVector3(g_mousePosX, g_mousePosY, 0); } 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_ESCAPE == key) { g_currentAction = MT_NULL; g_bDrawExtension = false; } } void _onMouseClick(Uint8 button) { if (button == SDL_BUTTON_LEFT) { switch (g_currentAction) { case MT_NULL: { g_currentTriangle.p0 = g_currentTriangle.p1 = fVector3(g_mousePosX, g_mousePosY, 0); g_currentAction = MT_FIRST_LINE; g_bDrawExtension = false; } break; case MT_FIRST_LINE: { g_currentTriangle.p1 = g_currentTriangle.p2 = fVector3(g_mousePosX, g_mousePosY, 0); g_currentAction = MT_TRIANGLE; g_bDrawExtension = true; } break; case MT_TRIANGLE: { g_currentTriangle.p2 = fVector3(g_mousePosX, g_mousePosY, 0); g_currentAction = MT_NULL; //build triangle fVector3 randColor = fVector3(rand() * 0.8f / RAND_MAX, rand() * 0.8f / RAND_MAX, rand() * 0.8f / RAND_MAX); g_currentTriangle.build(randColor, g_canvasWidth, g_canvasHeight, true); g_allTriangles.push_back(g_currentTriangle); g_bDrawExtension = true; } break; default: break; } } else if (button== SDL_BUTTON_RIGHT) { g_currentAction = MT_NULL; g_bDrawExtension = false; } } 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); fVector3 randColor = fVector3(rand() * 0.8f / RAND_MAX, rand() * 0.8f / RAND_MAX, rand() * 0.8f / RAND_MAX); Triangle triangle(p0, p1, p2); triangle.build(randColor, g_canvasWidth, g_canvasHeight, false); 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; } _onFramebufferSize(g_viewWidth, g_viewHeight); _buildDemoTriangles(); 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_UP: { _onMouseClick(event->button.button); } break; } return SDL_APP_CONTINUE; } SDL_AppResult SDL_AppIterate(void* appstate) { SDL_FRect rect; SDL_SetRenderDrawColor(g_renderer, 255, 255, 255, SDL_ALPHA_OPAQUE); SDL_RenderClear(g_renderer); _drawGrid(); _drawTriangles(); _drawAction(); _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) { }