// MIT License // // Copyright (C) 2018-2023, Tellusim Technologies Inc. https://tellusim.com/ // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in all // copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. #include #include #include #include #include /* */ using namespace Tellusim; /* */ int32_t main(int32_t argc, char **argv) { using Tellusim::sin; using Tellusim::cos; DECLARE_WINDOW if(!window) return 1; // create window String title = String::format("%s Tellusim::Canvas", window.getPlatformName()); if(!window.create(title) || !window.setHidden(false)) return 1; // create device Device device(window); if(!device) return 1; // create canvas Canvas canvas; canvas.setViewport(window.getWidth(), window.getHeight()); // create texture Texture texture = device.loadTexture("texture.png", Texture::FlagMipmaps); if(!texture) return 1; // canvas meshes uint32_t grid_width = 128; uint32_t grid_height = 64; float32_t dx = (float32_t)window.getWidth() / grid_width; float32_t dy = (float32_t)window.getHeight() / grid_height; for(uint32_t y = 0; y < grid_height; y++) { float32_t y0 = dy * y + dy * 0.25f; float32_t y1 = y0 + dy * 0.5f; for(uint32_t x = 0; x < grid_width; x++) { float32_t x0 = dx * x + dx * 0.25f; float32_t x1 = x0 + dx * 0.5f; CanvasMesh mesh(canvas); uint32_t i0 = mesh.addVertex(x0, y0, 0xff888888); uint32_t i1 = mesh.addVertex(x1, y0, 0xff888888); uint32_t i2 = mesh.addVertex(x1, y1, 0xff888888); uint32_t i3 = mesh.addVertex(x0, y1, 0xff888888); mesh.addIndices(i0, i1, i2); mesh.addIndices(i2, i3, i0); } } // canvas rectangles float32_t radiuses[] = { 16.0f, 32.0f, 64.0f, 16.0f, 32.0f, 48.0f, }; CanvasElement::Mode modes[] = { CanvasElement::ModeTextureCubic, CanvasElement::ModeTextureCubic3x3, CanvasElement::ModeTextureCubic5x5, }; Array rects; float32_t step = (float32_t)window.getWidth() / 4.0f; for(uint32_t i = 0; i < TS_COUNTOF(radiuses); i++) { float32_t x = step * (i % 3) + step; float32_t y = window.getHeight() - step * 0.5f; Vector2f size = Vector2f(step * 0.75f / (i / 3 + 1)); CanvasRect rect(radiuses[i], size, canvas); rect.setStrokeColor(Color(0.75f, 0.75f, 0.75f, 1.0f)); rect.setPosition(x, y); if(i < 3) { rect.setOrder(1); rect.setMipmap(1); rect.setMode(modes[i]); rect.setTexture(texture); rect.setColor(0.8f, 0.8f, 0.8f, 1.0f); } else { rect.setOrder(2); rect.setColor(Color::zero); } rects.append(rect); } // canvas meshes for(uint32_t i = 0; i < TS_COUNTOF(modes); i++) { float32_t x0 = step * i + step * 0.625f; float32_t y0 = step * 0.125f; float32_t x1 = x0 + step * 0.75f; float32_t y1 = y0 + step * 0.75f; CanvasMesh mesh(canvas); mesh.setOrder(1); mesh.setMipmap(1); mesh.setMode(modes[i]); mesh.setTexture(texture); mesh.addVertex(x0, y0, 0.0f, 0.0f, 1.0f); mesh.addVertex(x1, y0, 0.0f, 1.0f, 1.0f); mesh.addVertex(x1, y1, 0.0f, 1.0f, 0.0f); mesh.addVertex(x0, y1, 0.0f, 0.0f, 0.0f); mesh.addIndices(0, 1, 2); mesh.addIndices(2, 3, 0); } // canvas strip primitive CanvasStrip strip(canvas); strip.setColor(1.0f, 1.0f, 1.0f, 0.5f); strip.setStrokeStyle(StrokeStyle(4.0f, Color(0.0f, 0.0f, 0.0f, 0.5f))); strip.setWidth(24.0f); strip.setOrder(2); for(uint32_t j = 0; j <= 512; j++) { float32_t angle = j / 128.0f * Pi2; float32_t radius = j * 0.25f + 256.0f; strip.addPosition(sin(angle) * radius, cos(angle) * radius); } // canvas line primitive CanvasMesh mesh(canvas); mesh.setPrimitive(Pipeline::PrimitiveLine); mesh.setOrder(3); for(uint32_t j = 0; j < 32; j++) { float32_t offset = j / 64.0f; float32_t radius = j / 128.0f + 0.75f; for(uint32_t i = 0; i <= 7; i++) { float32_t angle = 2.0f * Pi2 * i / 7.0f + offset; uint32_t index = mesh.addVertex(sin(angle) * radius, cos(angle) * radius, 0xff000000u | (j << 2) | (j << 10) | (j << 18)); if(i) mesh.addIndices(index - 1, index); } } // tiger shapes Xml tiger_xml; Canvas tiger_canvas; tiger_canvas.setParent(canvas); if(!tiger_xml.load("tiger.svg")) return 1; const Xml tiger_group_xml = tiger_xml.getChild("g"); if(!tiger_group_xml) return 1; for(uint32_t i = 0; i < tiger_group_xml.getNumChildren(); i++) { const Xml xml = tiger_group_xml.getChild(i); if(xml.getName() == "g" && xml.isChild("path") && xml.isAttribute("fill")) { CanvasShape shape(tiger_canvas); if(!shape.createSVG(xml.getChild("path").getAttribute("d").get())) return 1; shape.setColor(Color(xml.getAttribute("fill").toRGBAu8())); if(xml.isAttribute("stroke")) { float32_t width = xml.getAttribute("stroke-width", 1.0f); float32_t offset = xml.getAttribute("stroke-width", 1.0f) * 0.5f; shape.setStrokeStyle(StrokeStyle(width, offset, Color(xml.getAttribute("stroke").toRGBAu8()))); } shape.setOrder(i); } } tiger_canvas.setTransform(Matrix4x4f::translate(1000.0f, 600.0f, 0.0f) * Matrix4x4f::scale(0.8f, -0.8f, 1.0f)); tiger_canvas.setOrder(1); // canvas ellipses Canvas ellipse_canvas; Array ellipses; ellipse_canvas.setParent(canvas); for(uint32_t i = 0; i < 16; i++) { CanvasEllipse ellipse(160.0f, ellipse_canvas); ellipse.setStrokeStyle(StrokeStyle(4.0f, Color(0.75f, 0.75f, 0.75f, 1.0f))); ellipse.setColor(Color::zero); ellipses.append(ellipse); ellipse.setOrder(3); } ellipse_canvas.setOrder(2); // canvas triangle Canvas triangle_canvas; Array triangles; triangle_canvas.setParent(canvas); for(uint32_t i = 0; i < 8; i++) { CanvasTriangle triangle(triangle_canvas); triangle.setStrokeStyle(StrokeStyle(8.0f, Color(0.75f, 0.75f, 0.75f, 1.0f))); triangle.setColor(Color::zero); triangles.append(triangle); } triangle_canvas.setOrder(3); // canvas gradients CanvasEllipse gradient_0(80.0f, canvas); CanvasEllipse gradient_1(80.0f, canvas); CanvasRect gradient_2(16.0f, Vector2f(128.0f), canvas); CanvasRect gradient_3(16.0f, Vector2f(128.0f), canvas); gradient_0.setMode(CanvasElement::ModeGradient); gradient_1.setMode(CanvasElement::ModeGradient); gradient_2.setMode(CanvasElement::ModeGradient); gradient_3.setMode(CanvasElement::ModeGradient); gradient_0.setPosition(96.0f, 128.0f); gradient_1.setPosition(canvas.getWidth() - 96.0f, 128.0f); gradient_2.setPosition(96.0f, canvas.getHeight() - 128.0f); gradient_3.setPosition(canvas.getWidth() - 96.0f, canvas.getHeight() - 128.0f); gradient_0.setGradientStyle(GradientStyle(0.75f, Vector2f(0.5f))); gradient_1.setGradientStyle(GradientStyle(1.0f, Vector2f(0.0f), Vector2f(1.0f, 0.0f))); gradient_2.setGradientStyle(GradientStyle(0.75f, Vector2f(0.5f))); gradient_3.setGradientStyle(GradientStyle(1.0f, Vector2f(0.0f), Vector2f(1.0f, 0.0f))); // canvas text Canvas text_canvas; CanvasText text(text_canvas); text_canvas.setParent(canvas); text.setAlign(CanvasElement::AlignCenter); text.setFontName("sansb.ttf"); text.setFontStyle(FontStyle(64, Color(0.9f, 0.1f, 0.1f, 1.0f))); text.getFontStyle().offset = Vector3f(4.0f, -4.0f, 0.0f); text.setText("Hello Canvas!!!"); text_canvas.setOrder(4); // create target Target target = device.createTarget(window); // main loop DECLARE_GLOBAL window.run([&]() -> bool { DECLARE_COMMON Window::update(); if(!window.render()) return false; // create canvas if(!canvas.create(device, target)) return false; // update elements Matrix4x4f center = Matrix4x4f::translate(canvas.getWidth() * 0.5f, canvas.getHeight() * 0.5f, 0.0f); mesh.setTransform(center * Matrix4x4f::rotateZ(time * 16.0f) * Matrix4x4f::scale(384.0f, 384.0f, 1.0f)); strip.setTransform(center * Matrix4x4f::rotateZ(time * 32.0f) * Matrix4x4f::scale(1.0f, 1.0f, 1.0f)); tiger_canvas.setTransform(center * Matrix4x4f::rotateZ(sin(time) * 16.0f) * Matrix4x4f::scale(0.8f, -0.8f, 1.0f) * Matrix4x4f::translate(-100.0f, -100.0f, 0.0f)); ellipse_canvas.setTransform(center); text_canvas.setTransform(center); strip.setWidth(24.0f + sin(time) * 8.0f); for(uint32_t i = 0; i < ellipses.size(); i++) { CanvasEllipse &ellipse = ellipses[i]; float32_t radius = 64.0f + sin(time * 2.0f + i) * 64.0f; ellipse.setPosition0(sin(time * 0.7f + i * 3.0f) * radius, cos(time * 1.3f) * radius, 0.0f); ellipse.setPosition1(cos(time * 0.7f + i * 4.0f) * radius, sin(time * 1.3f) * radius, 0.0f); } for(uint32_t i = 0; i < rects.size(); i++) { CanvasRect &rect = rects[i]; rect.getStrokeStyle().width = 24.0f + sin(time + i * 3.0f) * 16.0f; rect.getStrokeStyle().offset = cos(time + i * 2.0f) * 8.0f; } for(uint32_t i = 0; i < triangles.size(); i++) { CanvasTriangle &triangle = triangles[i]; float32_t width = (i < 4) ? 64.0f : -64.0f; float32_t x = (i < 4) ? 64.0f : canvas.getWidth() - 64.0f; triangle.setPosition0(x, canvas.getHeight() * 0.5f); triangle.setPosition1(x + width, canvas.getHeight() * 0.5f - 64.0f); triangle.setPosition2(x + width, canvas.getHeight() * 0.5f + 64.0f); triangle.setRadius((i & 3) * 12.0f + sin(time) * 16.0f); } gradient_0.getGradientStyle().center = Vector2f(0.5f + sin(time) * 0.25f, 0.5f + cos(time) * 0.25f); gradient_2.getGradientStyle().center = Vector2f(0.5f + sin(time) * 0.25f, 0.5f + cos(time) * 0.25f); gradient_1.getGradientStyle().center = Vector2f(0.5f - sin(time) * 0.5f, 0.5f - cos(time) * 0.5f); gradient_3.getGradientStyle().center = Vector2f(0.5f - sin(time) * 0.5f, 0.5f - cos(time) * 0.5f); gradient_1.getGradientStyle().axis = Vector2f(sin(time), cos(time)); gradient_3.getGradientStyle().axis = Vector2f(sin(time), cos(time)); // window target target.setClearColor(0.2f, 0.2f, 0.2f, 1.0f); target.begin(); { // create command list Command command = device.createCommand(target); // draw canvas canvas.draw(command, target); } target.end(); if(!window.present()) return false; if(!device.check()) return false; return true; }); // finish context window.finish(); return 0; }