fix SoftNcRunner GM code normalization.
This commit is contained in:
@@ -0,0 +1,170 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Color Guide System | HiAPI-C# 2025 </title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="title" content="Color Guide System | HiAPI-C# 2025 ">
|
||||
|
||||
|
||||
<link rel="icon" href="../../../img/HiAPI.favicon.ico">
|
||||
<link rel="stylesheet" href="../../../public/docfx.min.css">
|
||||
<link rel="stylesheet" href="../../../public/main.css">
|
||||
<meta name="docfx:navrel" content="../../../toc.html">
|
||||
<meta name="docfx:tocrel" content="../../toc.html">
|
||||
|
||||
<meta name="docfx:rel" content="../../../">
|
||||
|
||||
|
||||
|
||||
<meta name="loc:inThisArticle" content="In this article">
|
||||
<meta name="loc:searchResultsCount" content="{count} results for "{query}"">
|
||||
<meta name="loc:searchNoResults" content="No results for "{query}"">
|
||||
<meta name="loc:tocFilter" content="Filter by title">
|
||||
<meta name="loc:nextArticle" content="Next">
|
||||
<meta name="loc:prevArticle" content="Previous">
|
||||
<meta name="loc:themeLight" content="Light">
|
||||
<meta name="loc:themeDark" content="Dark">
|
||||
<meta name="loc:themeAuto" content="Auto">
|
||||
<meta name="loc:changeTheme" content="Change theme">
|
||||
<meta name="loc:copy" content="Copy">
|
||||
<meta name="loc:downloadPdf" content="Download PDF">
|
||||
|
||||
<script type="module" src="./../../../public/docfx.min.js"></script>
|
||||
|
||||
<script>
|
||||
const theme = localStorage.getItem('theme') || 'auto'
|
||||
document.documentElement.setAttribute('data-bs-theme', theme === 'auto' ? (window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light') : theme)
|
||||
</script>
|
||||
|
||||
</head>
|
||||
|
||||
<body class="tex2jax_ignore" data-layout="" data-yaml-mime="">
|
||||
<header class="bg-body border-bottom">
|
||||
<nav id="autocollapse" class="navbar navbar-expand-md" role="navigation">
|
||||
<div class="container-xxl flex-nowrap">
|
||||
<a class="navbar-brand" href="../../../index.html">
|
||||
<img id="logo" class="svg" src="../../../img/HiAPI.logo.png" alt="">
|
||||
|
||||
</a>
|
||||
<button class="btn btn-lg d-md-none border-0" type="button" data-bs-toggle="collapse" data-bs-target="#navpanel" aria-controls="navpanel" aria-expanded="false" aria-label="Toggle navigation">
|
||||
<i class="bi bi-three-dots"></i>
|
||||
</button>
|
||||
<div class="collapse navbar-collapse" id="navpanel">
|
||||
<div id="navbar">
|
||||
<form class="search" role="search" id="search">
|
||||
<i class="bi bi-search"></i>
|
||||
<input class="form-control" id="search-query" type="search" disabled placeholder="Search" autocomplete="off" aria-label="Search">
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
</header>
|
||||
|
||||
<main class="container-xxl">
|
||||
<div class="toc-offcanvas">
|
||||
<div class="offcanvas-md offcanvas-start" tabindex="-1" id="tocOffcanvas" aria-labelledby="tocOffcanvasLabel">
|
||||
<div class="offcanvas-header">
|
||||
<h5 class="offcanvas-title" id="tocOffcanvasLabel">Table of Contents</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="offcanvas" data-bs-target="#tocOffcanvas" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="offcanvas-body">
|
||||
<nav class="toc" id="toc"></nav>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="content">
|
||||
<div class="actionbar">
|
||||
<button class="btn btn-lg border-0 d-md-none" type="button" data-bs-toggle="offcanvas" data-bs-target="#tocOffcanvas" aria-controls="tocOffcanvas" aria-expanded="false" aria-label="Show table of contents">
|
||||
<i class="bi bi-list"></i>
|
||||
</button>
|
||||
|
||||
<nav id="breadcrumb"></nav>
|
||||
</div>
|
||||
|
||||
<article data-uid="">
|
||||
<h1 id="color-guide-system">Color Guide System</h1>
|
||||
|
||||
<p>The Color Guide System allows you to assign colors and rendering priorities to visual elements based on machining steps or data states.</p>
|
||||
<h2 id="overview">Overview</h2>
|
||||
<p>The <a class="xref" href="../../../api/Hi.Coloring.IColorGuide.html">IColorGuide</a> interface defines the core functionality for color mapping, allowing different colors and rendering priorities to be returned based on various steps or states. This system is particularly suitable for scenarios requiring visual encoding based on data states, such as CNC machining path visualization.</p>
|
||||
<h2 id="core-interface">Core Interface</h2>
|
||||
<h3 id="icolorguide-interface">IColorGuide Interface</h3>
|
||||
<p><a class="xref" href="../../../api/Hi.Coloring.IColorGuide.html">IColorGuide</a> is the core interface of the Color Guide System, inheriting from <a class="xref" href="../../../api/Hi.Common.XmlUtils.IMakeXmlSource.html">IMakeXmlSource</a> and <a class="xref" href="../../../api/Hi.Coloring.IGetColorGuide.html">IGetColorGuide</a>.</p>
|
||||
<h4 id="methods">Methods</h4>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Method</th>
|
||||
<th>Description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><a class="xref" href="../../../api/Hi.Coloring.IColorGuide.html#Hi_Coloring_IColorGuide_GetRgb_">GetRgb</a></td>
|
||||
<td>Returns RGB color value based on the step object</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a class="xref" href="../../../api/Hi.Coloring.IColorGuide.html#Hi_Coloring_IColorGuide_GetRgbWithPriority_">GetRgbWithPriority</a></td>
|
||||
<td>Returns RGB color and rendering priority</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<h4 id="priority-explanation">Priority Explanation</h4>
|
||||
<p>The <code>attachmentPriority</code> parameter controls the overlay priority during rendering:</p>
|
||||
<ul>
|
||||
<li><strong>Higher values take priority</strong>: Larger priority values are displayed first</li>
|
||||
<li><strong>Graph scaling for pixel consolidation</strong>: When multiple machining steps are rendered within the same pixel, higher priority colors take precedence</li>
|
||||
</ul>
|
||||
<h4 id="effects-on-rendering-systems">Effects on Rendering Systems</h4>
|
||||
<p><strong>In CubeTree (<a class="xref" href="../../../api/Hi.Cbtr.CubeTree.html">CubeTree</a>):</strong></p>
|
||||
<ul>
|
||||
<li>Color priorities determine which machining state is displayed when multiple operations overlap in 3D space</li>
|
||||
<li>Higher priority colors (like collision detection) will override lower priority colors (like normal cutting)</li>
|
||||
</ul>
|
||||
<h2 id="application-scenarios">Application Scenarios</h2>
|
||||
<p>The Color Guide System is suitable for the following scenarios:</p>
|
||||
<ol>
|
||||
<li><strong>CNC Machining Visualization</strong>: Display different path colors based on machining states</li>
|
||||
<li><strong>Data State Encoding</strong>: Convert numerical states to visual color representations</li>
|
||||
<li><strong>Priority-based Graph Scaling</strong>: When zooming out or viewing dense data, higher priority colors (critical states) remain visible while lower priority colors may be consolidated</li>
|
||||
<li><strong>Multi-resolution Rendering</strong>: Critical machining issues (collisions, safety violations) are always displayed regardless of zoom level or data density</li>
|
||||
</ol>
|
||||
<h2 id="registering-color-guide-in-project">Registering Color Guide in Project</h2>
|
||||
<p>To make the Color Guide effective in a project, implement the <a class="xref" href="../../../api/Hi.Coloring.IColorGuide.html">IColorGuide</a> interface and register it in the project's color guide dictionary.</p>
|
||||
<h2 id="xml-serialization">XML Serialization</h2>
|
||||
<p>See <a href="../../common/xml-io.html">About XML IO</a> for details on XML serialization implementation.</p>
|
||||
<h2 id="wpf-application-source-and-sample-code-path">WPF Application Source And Sample Code Path</h2>
|
||||
<ul>
|
||||
<li>HiMech/Coloring/IColorGuide</li>
|
||||
<li>HiNC-2025-win-desktop/Demo/DemoColorGuide</li>
|
||||
</ul>
|
||||
<p>See <a href="../../../app-anatomy/index.html">this page</a> for Git repository information.</p>
|
||||
|
||||
</article>
|
||||
|
||||
<div class="contribution d-print-none">
|
||||
</div>
|
||||
|
||||
<div class="next-article d-print-none border-top" id="nextArticle"></div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="affix">
|
||||
<nav id="affix"></nav>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<div class="container-xxl search-results" id="search-results"></div>
|
||||
|
||||
<footer class="border-top text-secondary">
|
||||
<div class="container-xxl">
|
||||
<div class="flex-fill">
|
||||
<span> Copyright © 2025 <a href='https://superhightech.com.tw'>Tech Coordinate</a>. All rights reserved. <a href='https://superhightech.com.tw'>超級高科技股份有限公司</a> © 2025 版權所有 </span>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 8.2 KiB |
@@ -0,0 +1,300 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Using Hi.Disp.Drawing | HiAPI-C# 2025 </title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="title" content="Using Hi.Disp.Drawing | HiAPI-C# 2025 ">
|
||||
|
||||
|
||||
<link rel="icon" href="../../../img/HiAPI.favicon.ico">
|
||||
<link rel="stylesheet" href="../../../public/docfx.min.css">
|
||||
<link rel="stylesheet" href="../../../public/main.css">
|
||||
<meta name="docfx:navrel" content="../../../toc.html">
|
||||
<meta name="docfx:tocrel" content="../../toc.html">
|
||||
|
||||
<meta name="docfx:rel" content="../../../">
|
||||
|
||||
|
||||
|
||||
<meta name="loc:inThisArticle" content="In this article">
|
||||
<meta name="loc:searchResultsCount" content="{count} results for "{query}"">
|
||||
<meta name="loc:searchNoResults" content="No results for "{query}"">
|
||||
<meta name="loc:tocFilter" content="Filter by title">
|
||||
<meta name="loc:nextArticle" content="Next">
|
||||
<meta name="loc:prevArticle" content="Previous">
|
||||
<meta name="loc:themeLight" content="Light">
|
||||
<meta name="loc:themeDark" content="Dark">
|
||||
<meta name="loc:themeAuto" content="Auto">
|
||||
<meta name="loc:changeTheme" content="Change theme">
|
||||
<meta name="loc:copy" content="Copy">
|
||||
<meta name="loc:downloadPdf" content="Download PDF">
|
||||
|
||||
<script type="module" src="./../../../public/docfx.min.js"></script>
|
||||
|
||||
<script>
|
||||
const theme = localStorage.getItem('theme') || 'auto'
|
||||
document.documentElement.setAttribute('data-bs-theme', theme === 'auto' ? (window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light') : theme)
|
||||
</script>
|
||||
|
||||
</head>
|
||||
|
||||
<body class="tex2jax_ignore" data-layout="" data-yaml-mime="">
|
||||
<header class="bg-body border-bottom">
|
||||
<nav id="autocollapse" class="navbar navbar-expand-md" role="navigation">
|
||||
<div class="container-xxl flex-nowrap">
|
||||
<a class="navbar-brand" href="../../../index.html">
|
||||
<img id="logo" class="svg" src="../../../img/HiAPI.logo.png" alt="">
|
||||
|
||||
</a>
|
||||
<button class="btn btn-lg d-md-none border-0" type="button" data-bs-toggle="collapse" data-bs-target="#navpanel" aria-controls="navpanel" aria-expanded="false" aria-label="Toggle navigation">
|
||||
<i class="bi bi-three-dots"></i>
|
||||
</button>
|
||||
<div class="collapse navbar-collapse" id="navpanel">
|
||||
<div id="navbar">
|
||||
<form class="search" role="search" id="search">
|
||||
<i class="bi bi-search"></i>
|
||||
<input class="form-control" id="search-query" type="search" disabled placeholder="Search" autocomplete="off" aria-label="Search">
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
</header>
|
||||
|
||||
<main class="container-xxl">
|
||||
<div class="toc-offcanvas">
|
||||
<div class="offcanvas-md offcanvas-start" tabindex="-1" id="tocOffcanvas" aria-labelledby="tocOffcanvasLabel">
|
||||
<div class="offcanvas-header">
|
||||
<h5 class="offcanvas-title" id="tocOffcanvasLabel">Table of Contents</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="offcanvas" data-bs-target="#tocOffcanvas" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="offcanvas-body">
|
||||
<nav class="toc" id="toc"></nav>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="content">
|
||||
<div class="actionbar">
|
||||
<button class="btn btn-lg border-0 d-md-none" type="button" data-bs-toggle="offcanvas" data-bs-target="#tocOffcanvas" aria-controls="tocOffcanvas" aria-expanded="false" aria-label="Show table of contents">
|
||||
<i class="bi bi-list"></i>
|
||||
</button>
|
||||
|
||||
<nav id="breadcrumb"></nav>
|
||||
</div>
|
||||
|
||||
<article data-uid="">
|
||||
<h1 id="using-hidispdrawing">Using Hi.Disp.Drawing</h1>
|
||||
|
||||
<p>The <a class="xref" href="../../../api/Hi.Disp.Drawing.html">Drawing</a> class is the most fundamental and efficient rendering unit that allows you to draw points, lines, and surfaces within the <a class="xref" href="../../../api/Hi.Disp.DispEngine.html">DispEngine</a>.</p>
|
||||
<h2 id="understanding-drawing-structure">Understanding Drawing Structure</h2>
|
||||
<p>Looking at the constructor <a class="xref" href="../../../api/Hi.Disp.Drawing.html#Hi_Disp_Drawing__ctor_System_Double___Hi_Disp_Stamp_System_Int32_">Drawing(double[], Stamp, int)</a> helps explain its structure:</p>
|
||||
<ul>
|
||||
<li>The <code>double[]</code> array contains batch data for rendering, composed of one or more data groups of consistent length</li>
|
||||
<li>Each data group's length is determined by the <a class="xref" href="../../../api/Hi.Disp.Stamp.html">Stamp</a> parameter</li>
|
||||
<li>Each data group describes a single vertex</li>
|
||||
</ul>
|
||||
<h2 id="data-components">Data Components</h2>
|
||||
<p>A data group can contain up to four types of information:</p>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Information</th>
|
||||
<th>Abbreviation</th>
|
||||
<th>Description</th>
|
||||
<th>Size</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><strong>Vertex</strong></td>
|
||||
<td>V</td>
|
||||
<td>The position of the point (x, y, z)</td>
|
||||
<td>3 doubles</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>Normal</strong></td>
|
||||
<td>N</td>
|
||||
<td>The normal vector affecting light reflection (Nx, Ny, Nz)</td>
|
||||
<td>3 doubles</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>Color</strong></td>
|
||||
<td>C</td>
|
||||
<td>RGB color values ranging from 0 to 1</td>
|
||||
<td>3 doubles</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>Pick ID</strong></td>
|
||||
<td>P</td>
|
||||
<td>A single double value converted from an integer for selection operations</td>
|
||||
<td>1 double</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<p>The <a class="xref" href="../../../api/Hi.Disp.Stamp.html">Stamp</a> enumeration combines these abbreviations to create these possible stamps: <code>{V, NV, CV, CNV, PV, PNV, PCV, PCNV}</code>.</p>
|
||||
<h3 id="important-notes">Important Notes:</h3>
|
||||
<ul>
|
||||
<li>The <strong>Vertex</strong> (V) is mandatory, which is why V appears in every Stamp option</li>
|
||||
<li><strong>Normal</strong> vectors (N) are typically used for 3D graphics to create a sense of depth through lighting</li>
|
||||
<li><strong>Color</strong> (C) uses three double values (R, G, B) in the range of 0 to 1</li>
|
||||
<li><strong>Pick ID</strong> (P) is used for graphical selection operations</li>
|
||||
</ul>
|
||||
<h2 id="data-structure-example">Data Structure Example</h2>
|
||||
<ul>
|
||||
<li>If <a class="xref" href="../../../api/Hi.Disp.Stamp.html">Stamp</a> is <code>V</code>, each data group consists of 3 double values (x, y, z)</li>
|
||||
<li>If <a class="xref" href="../../../api/Hi.Disp.Stamp.html">Stamp</a> is <code>PCV</code>, each data group consists of 1(P) + 3(C) + 3(V) = 7 double values</li>
|
||||
</ul>
|
||||
<h2 id="rendering-mode">Rendering Mode</h2>
|
||||
<p>The <code>glmode</code> parameter is an OpenGL constant that specifies the drawing mode. You can search for “OpenGL Primitives” online to see illustrations of these modes.</p>
|
||||
<h2 id="example-usage">Example Usage</h2>
|
||||
<pre><code class="lang-csharp">// Creating a simple line strip with three vertices
|
||||
double[] vertices = new double[] {
|
||||
0, 0, 0, // First point at origin
|
||||
1, 0, 0, // Second point along X-axis
|
||||
0, 0, 1 // Third point along Z-axis
|
||||
};
|
||||
|
||||
// Create drawing object using the vertices
|
||||
var drawing = new Drawing(vertices, Stamp.V, (int)OpenGL.GL_LINE_STRIP);
|
||||
</code></pre>
|
||||
<p>This example creates three vertices with only position information (V), so each vertex has just xyz coordinates. The drawing mode is set to LineStrip.</p>
|
||||
<p><img src="easydraw_lines.png" alt="Line Strip Drawing Example"></p>
|
||||
<h2 id="performance-considerations">Performance Considerations</h2>
|
||||
<div class="NOTE">
|
||||
<h5>Note</h5>
|
||||
<p>After a <a class="xref" href="../../../api/Hi.Disp.Drawing.html">Drawing</a> object is created, its source data is stored in GPU memory. Regardless of the amount of data, the CPU processing load when calling <a class="xref" href="../../../api/Hi.Disp.IDisplayee.html#Hi_Disp_IDisplayee_Display_Hi_Disp_Bind_">Display(Bind)</a> remains consistent. This means displaying 100 points with one <a class="xref" href="../../../api/Hi.Disp.Drawing.html">Drawing</a> object is approximately 100 times faster than using 100 separate Drawing objects to display 100 individual points.</p>
|
||||
</div>
|
||||
<h2 id="composing-multiple-idisplayee-objects">Composing Multiple IDisplayee Objects</h2>
|
||||
<p>A common pattern is to combine multiple <a class="xref" href="../../../api/Hi.Disp.IDisplayee.html">IDisplayee</a> objects, including <a class="xref" href="../../../api/Hi.Disp.Drawing.html">Drawing</a> objects:</p>
|
||||
<pre><code class="lang-csharp">public class MyCompositeDisplayee : IDisplayee
|
||||
{
|
||||
private readonly List<IDisplayee> _displayees = new List<IDisplayee>();
|
||||
|
||||
public MyCompositeDisplayee()
|
||||
{
|
||||
// Create a grid drawing
|
||||
_displayees.Add(CreateGridDrawing());
|
||||
|
||||
// Create an axes drawing
|
||||
_displayees.Add(CreateAxesDrawing());
|
||||
|
||||
// Add other custom drawings
|
||||
_displayees.Add(CreateCustomDrawing());
|
||||
}
|
||||
|
||||
private Drawing CreateGridDrawing()
|
||||
{
|
||||
// Code to create a grid
|
||||
double[] gridVertices = new double[/* grid data */];
|
||||
return new Drawing(gridVertices, Stamp.CV, (int)OpenGL.GL_LINES);
|
||||
}
|
||||
|
||||
private Drawing CreateAxesDrawing()
|
||||
{
|
||||
// Create colored axes
|
||||
double[] axesData = new double[] {
|
||||
// Red X-axis (with color)
|
||||
1, 0, 0, 0, 0, 0, // Red color, origin
|
||||
1, 0, 0, 1, 0, 0, // Red color, x-axis end
|
||||
|
||||
// Green Y-axis (with color)
|
||||
0, 1, 0, 0, 0, 0, // Green color, origin
|
||||
0, 1, 0, 0, 1, 0, // Green color, y-axis end
|
||||
|
||||
// Blue Z-axis (with color)
|
||||
0, 0, 1, 0, 0, 0, // Blue color, origin
|
||||
0, 0, 1, 0, 0, 1 // Blue color, z-axis end
|
||||
};
|
||||
|
||||
return new Drawing(axesData, Stamp.CV, (int)OpenGL.GL_LINES);
|
||||
}
|
||||
|
||||
public void Display(Bind bind)
|
||||
{
|
||||
// Render all contained displayees
|
||||
foreach (var displayee in _displayees)
|
||||
{
|
||||
displayee.Display(bind);
|
||||
}
|
||||
}
|
||||
|
||||
public void ExpandToBox3d(Box3d box)
|
||||
{
|
||||
// Update bounding box based on all displayees
|
||||
foreach (var displayee in _displayees)
|
||||
{
|
||||
displayee.ExpandToBox3d(box);
|
||||
}
|
||||
}
|
||||
}
|
||||
</code></pre>
|
||||
<h2 id="creating-common-shapes">Creating Common Shapes</h2>
|
||||
<p>Here are some examples of creating common shapes using the <a class="xref" href="../../../api/Hi.Disp.Drawing.html">Drawing</a> class:</p>
|
||||
<h3 id="creating-points">Creating Points</h3>
|
||||
<pre><code class="lang-csharp">// Create an array of points
|
||||
double[] pointData = new double[] {
|
||||
0, 0, 0, // Point 1
|
||||
1, 1, 1, // Point 2
|
||||
2, 0, 0, // Point 3
|
||||
0, 2, 0 // Point 4
|
||||
};
|
||||
|
||||
// Create a Drawing for points
|
||||
var pointDrawing = new Drawing(pointData, Stamp.V, (int)OpenGL.GL_POINTS);
|
||||
</code></pre>
|
||||
<h3 id="creating-lines">Creating Lines</h3>
|
||||
<pre><code class="lang-csharp">// Create line segments (pairs of vertices)
|
||||
double[] lineData = new double[] {
|
||||
0, 0, 0, 1, 1, 0, // Line 1: (0,0,0) to (1,1,0)
|
||||
2, 0, 0, 2, 2, 0 // Line 2: (2,0,0) to (2,2,0)
|
||||
};
|
||||
|
||||
// Create a Drawing for lines
|
||||
var lineDrawing = new Drawing(lineData, Stamp.V, (int)OpenGL.GL_LINES);
|
||||
</code></pre>
|
||||
<h3 id="creating-triangles">Creating Triangles</h3>
|
||||
<pre><code class="lang-csharp">// Create triangles (triplets of vertices)
|
||||
double[] triangleData = new double[] {
|
||||
// Triangle 1
|
||||
0, 0, 0, // Vertex 1
|
||||
1, 0, 0, // Vertex 2
|
||||
0, 1, 0 // Vertex 3
|
||||
};
|
||||
|
||||
// Create a Drawing for triangles
|
||||
var triangleDrawing = new Drawing(triangleData, Stamp.V, (int)OpenGL.GL_TRIANGLES);
|
||||
</code></pre>
|
||||
<h2 id="see-also">See Also</h2>
|
||||
<ul>
|
||||
<li><a class="xref" href="../../../api/Hi.Disp.DispEngine.html">DispEngine</a></li>
|
||||
<li><a class="xref" href="../../../api/Hi.Disp.IDisplayee.html">IDisplayee</a></li>
|
||||
<li><a class="xref" href="../../../api/Hi.Disp.DispList.html">DispList</a></li>
|
||||
</ul>
|
||||
|
||||
</article>
|
||||
|
||||
<div class="contribution d-print-none">
|
||||
</div>
|
||||
|
||||
<div class="next-article d-print-none border-top" id="nextArticle"></div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="affix">
|
||||
<nav id="affix"></nav>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<div class="container-xxl search-results" id="search-results"></div>
|
||||
|
||||
<footer class="border-top text-secondary">
|
||||
<div class="container-xxl">
|
||||
<div class="flex-fill">
|
||||
<span> Copyright © 2025 <a href='https://superhightech.com.tw'>Tech Coordinate</a>. All rights reserved. <a href='https://superhightech.com.tw'>超級高科技股份有限公司</a> © 2025 版權所有 </span>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,175 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Rendering with HiAPI | HiAPI-C# 2025 </title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="title" content="Rendering with HiAPI | HiAPI-C# 2025 ">
|
||||
|
||||
|
||||
<link rel="icon" href="../../img/HiAPI.favicon.ico">
|
||||
<link rel="stylesheet" href="../../public/docfx.min.css">
|
||||
<link rel="stylesheet" href="../../public/main.css">
|
||||
<meta name="docfx:navrel" content="../../toc.html">
|
||||
<meta name="docfx:tocrel" content="../toc.html">
|
||||
|
||||
<meta name="docfx:rel" content="../../">
|
||||
|
||||
|
||||
|
||||
<meta name="loc:inThisArticle" content="In this article">
|
||||
<meta name="loc:searchResultsCount" content="{count} results for "{query}"">
|
||||
<meta name="loc:searchNoResults" content="No results for "{query}"">
|
||||
<meta name="loc:tocFilter" content="Filter by title">
|
||||
<meta name="loc:nextArticle" content="Next">
|
||||
<meta name="loc:prevArticle" content="Previous">
|
||||
<meta name="loc:themeLight" content="Light">
|
||||
<meta name="loc:themeDark" content="Dark">
|
||||
<meta name="loc:themeAuto" content="Auto">
|
||||
<meta name="loc:changeTheme" content="Change theme">
|
||||
<meta name="loc:copy" content="Copy">
|
||||
<meta name="loc:downloadPdf" content="Download PDF">
|
||||
|
||||
<script type="module" src="./../../public/docfx.min.js"></script>
|
||||
|
||||
<script>
|
||||
const theme = localStorage.getItem('theme') || 'auto'
|
||||
document.documentElement.setAttribute('data-bs-theme', theme === 'auto' ? (window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light') : theme)
|
||||
</script>
|
||||
|
||||
</head>
|
||||
|
||||
<body class="tex2jax_ignore" data-layout="" data-yaml-mime="">
|
||||
<header class="bg-body border-bottom">
|
||||
<nav id="autocollapse" class="navbar navbar-expand-md" role="navigation">
|
||||
<div class="container-xxl flex-nowrap">
|
||||
<a class="navbar-brand" href="../../index.html">
|
||||
<img id="logo" class="svg" src="../../img/HiAPI.logo.png" alt="">
|
||||
|
||||
</a>
|
||||
<button class="btn btn-lg d-md-none border-0" type="button" data-bs-toggle="collapse" data-bs-target="#navpanel" aria-controls="navpanel" aria-expanded="false" aria-label="Toggle navigation">
|
||||
<i class="bi bi-three-dots"></i>
|
||||
</button>
|
||||
<div class="collapse navbar-collapse" id="navpanel">
|
||||
<div id="navbar">
|
||||
<form class="search" role="search" id="search">
|
||||
<i class="bi bi-search"></i>
|
||||
<input class="form-control" id="search-query" type="search" disabled placeholder="Search" autocomplete="off" aria-label="Search">
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
</header>
|
||||
|
||||
<main class="container-xxl">
|
||||
<div class="toc-offcanvas">
|
||||
<div class="offcanvas-md offcanvas-start" tabindex="-1" id="tocOffcanvas" aria-labelledby="tocOffcanvasLabel">
|
||||
<div class="offcanvas-header">
|
||||
<h5 class="offcanvas-title" id="tocOffcanvasLabel">Table of Contents</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="offcanvas" data-bs-target="#tocOffcanvas" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="offcanvas-body">
|
||||
<nav class="toc" id="toc"></nav>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="content">
|
||||
<div class="actionbar">
|
||||
<button class="btn btn-lg border-0 d-md-none" type="button" data-bs-toggle="offcanvas" data-bs-target="#tocOffcanvas" aria-controls="tocOffcanvas" aria-expanded="false" aria-label="Show table of contents">
|
||||
<i class="bi bi-list"></i>
|
||||
</button>
|
||||
|
||||
<nav id="breadcrumb"></nav>
|
||||
</div>
|
||||
|
||||
<article data-uid="">
|
||||
<h1 id="rendering-with-hiapi">Rendering with HiAPI</h1>
|
||||
|
||||
<p>This section covers the rendering capabilities of HiAPI, focusing on how to create and display visual content in your applications.</p>
|
||||
<h2 id="overview">Overview</h2>
|
||||
<p>HiAPI provides a powerful rendering system built around the <a class="xref" href="../../api/Hi.Disp.DispEngine.html">DispEngine</a> and <a class="xref" href="../../api/Hi.Disp.IDisplayee.html">IDisplayee</a> interface. This system enables you to:</p>
|
||||
<ul>
|
||||
<li>Create and render 3D and 2D graphics</li>
|
||||
<li>Implement interactive user interfaces</li>
|
||||
<li>Achieve high-performance rendering across multiple platforms</li>
|
||||
<li>Handle touch, mouse, and keyboard input uniformly</li>
|
||||
</ul>
|
||||
<h2 id="key-components">Key Components</h2>
|
||||
<p>The HiAPI rendering system consists of several key components:</p>
|
||||
<ul>
|
||||
<li><strong>DispEngine</strong>: The core rendering engine that processes displayees and handles user interaction</li>
|
||||
<li><strong>IDisplayee</strong>: The interface for renderable objects</li>
|
||||
<li><strong>Drawing</strong>: A fundamental rendering unit for creating basic geometric elements</li>
|
||||
<li><strong>RenderingCanvas</strong>: UI controls for different frameworks that host the DispEngine</li>
|
||||
</ul>
|
||||
<h2 id="sections">Sections</h2>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Topic</th>
|
||||
<th>Description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><a href="rendering-canvas/index.html">Using RenderingCanvas with DispEngine</a></td>
|
||||
<td>Learn how to use the RenderingCanvas component in your applications</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="rendering-canvas/custom-implementation.html">Building Your Own Rendering Canvas</a></td>
|
||||
<td>Understand how to implement custom rendering components</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="drawing/index.html">Drawing</a></td>
|
||||
<td>Learn how to use the Drawing class to create basic geometric elements</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="color-guide/index.html">Color Guide System</a></td>
|
||||
<td>Learn how to implement color mapping and rendering priority for steps</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<h2 id="basic-rendering-workflow">Basic Rendering Workflow</h2>
|
||||
<p>The typical workflow for rendering with HiAPI follows these steps:</p>
|
||||
<ol>
|
||||
<li><strong>Create Displayees</strong>: Implement <a class="xref" href="../../api/Hi.Disp.IDisplayee.html">IDisplayee</a> or use existing implementations like <a class="xref" href="../../api/Hi.Disp.Drawing.html">Drawing</a></li>
|
||||
<li><strong>Configure DispEngine</strong>: Create and initialize a <a class="xref" href="../../api/Hi.Disp.DispEngine.html">DispEngine</a> with your displayees</li>
|
||||
<li><strong>UI Integration</strong>: Use RenderingCanvas components to display the rendered content in your UI</li>
|
||||
<li><strong>Handle Input</strong>: Process user interactions through the DispEngine's input handling methods</li>
|
||||
</ol>
|
||||
<p>This pattern works consistently across all supported UI frameworks, allowing you to develop cross-platform applications with a unified codebase.</p>
|
||||
<h2 id="see-also">See Also</h2>
|
||||
<ul>
|
||||
<li><a class="xref" href="../../api/Hi.Disp.DispEngine.html">DispEngine</a></li>
|
||||
<li><a class="xref" href="../../api/Hi.Disp.IDisplayee.html">IDisplayee</a></li>
|
||||
<li><a class="xref" href="../../api/Hi.Disp.Drawing.html">Drawing</a></li>
|
||||
<li><a class="xref" href="../../api/Hi.Disp.DispList.html">DispList</a></li>
|
||||
</ul>
|
||||
|
||||
</article>
|
||||
|
||||
<div class="contribution d-print-none">
|
||||
</div>
|
||||
|
||||
<div class="next-article d-print-none border-top" id="nextArticle"></div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="affix">
|
||||
<nav id="affix"></nav>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<div class="container-xxl search-results" id="search-results"></div>
|
||||
|
||||
<footer class="border-top text-secondary">
|
||||
<div class="container-xxl">
|
||||
<div class="flex-fill">
|
||||
<span> Copyright © 2025 <a href='https://superhightech.com.tw'>Tech Coordinate</a>. All rights reserved. <a href='https://superhightech.com.tw'>超級高科技股份有限公司</a> © 2025 版權所有 </span>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
+904
@@ -0,0 +1,904 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Building Your Own Rendering Canvas | HiAPI-C# 2025 </title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="title" content="Building Your Own Rendering Canvas | HiAPI-C# 2025 ">
|
||||
|
||||
|
||||
<link rel="icon" href="../../../img/HiAPI.favicon.ico">
|
||||
<link rel="stylesheet" href="../../../public/docfx.min.css">
|
||||
<link rel="stylesheet" href="../../../public/main.css">
|
||||
<meta name="docfx:navrel" content="../../../toc.html">
|
||||
<meta name="docfx:tocrel" content="../../toc.html">
|
||||
|
||||
<meta name="docfx:rel" content="../../../">
|
||||
|
||||
|
||||
|
||||
<meta name="loc:inThisArticle" content="In this article">
|
||||
<meta name="loc:searchResultsCount" content="{count} results for "{query}"">
|
||||
<meta name="loc:searchNoResults" content="No results for "{query}"">
|
||||
<meta name="loc:tocFilter" content="Filter by title">
|
||||
<meta name="loc:nextArticle" content="Next">
|
||||
<meta name="loc:prevArticle" content="Previous">
|
||||
<meta name="loc:themeLight" content="Light">
|
||||
<meta name="loc:themeDark" content="Dark">
|
||||
<meta name="loc:themeAuto" content="Auto">
|
||||
<meta name="loc:changeTheme" content="Change theme">
|
||||
<meta name="loc:copy" content="Copy">
|
||||
<meta name="loc:downloadPdf" content="Download PDF">
|
||||
|
||||
<script type="module" src="./../../../public/docfx.min.js"></script>
|
||||
|
||||
<script>
|
||||
const theme = localStorage.getItem('theme') || 'auto'
|
||||
document.documentElement.setAttribute('data-bs-theme', theme === 'auto' ? (window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light') : theme)
|
||||
</script>
|
||||
|
||||
</head>
|
||||
|
||||
<body class="tex2jax_ignore" data-layout="" data-yaml-mime="">
|
||||
<header class="bg-body border-bottom">
|
||||
<nav id="autocollapse" class="navbar navbar-expand-md" role="navigation">
|
||||
<div class="container-xxl flex-nowrap">
|
||||
<a class="navbar-brand" href="../../../index.html">
|
||||
<img id="logo" class="svg" src="../../../img/HiAPI.logo.png" alt="">
|
||||
|
||||
</a>
|
||||
<button class="btn btn-lg d-md-none border-0" type="button" data-bs-toggle="collapse" data-bs-target="#navpanel" aria-controls="navpanel" aria-expanded="false" aria-label="Toggle navigation">
|
||||
<i class="bi bi-three-dots"></i>
|
||||
</button>
|
||||
<div class="collapse navbar-collapse" id="navpanel">
|
||||
<div id="navbar">
|
||||
<form class="search" role="search" id="search">
|
||||
<i class="bi bi-search"></i>
|
||||
<input class="form-control" id="search-query" type="search" disabled placeholder="Search" autocomplete="off" aria-label="Search">
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
</header>
|
||||
|
||||
<main class="container-xxl">
|
||||
<div class="toc-offcanvas">
|
||||
<div class="offcanvas-md offcanvas-start" tabindex="-1" id="tocOffcanvas" aria-labelledby="tocOffcanvasLabel">
|
||||
<div class="offcanvas-header">
|
||||
<h5 class="offcanvas-title" id="tocOffcanvasLabel">Table of Contents</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="offcanvas" data-bs-target="#tocOffcanvas" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="offcanvas-body">
|
||||
<nav class="toc" id="toc"></nav>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="content">
|
||||
<div class="actionbar">
|
||||
<button class="btn btn-lg border-0 d-md-none" type="button" data-bs-toggle="offcanvas" data-bs-target="#tocOffcanvas" aria-controls="tocOffcanvas" aria-expanded="false" aria-label="Show table of contents">
|
||||
<i class="bi bi-list"></i>
|
||||
</button>
|
||||
|
||||
<nav id="breadcrumb"></nav>
|
||||
</div>
|
||||
|
||||
<article data-uid="">
|
||||
<h1 id="building-your-own-rendering-canvas">Building Your Own Rendering Canvas</h1>
|
||||
|
||||
<p>This guide provides detailed implementation information for creating your own <code>RenderingCanvas</code> using the <a class="xref" href="../../../api/Hi.Disp.DispEngine.html">DispEngine</a>. By understanding these implementation details, you can customize the rendering component for specific application needs or create implementations for other UI frameworks.</p>
|
||||
<div class="NOTE">
|
||||
<h5>Note</h5>
|
||||
<p><strong>For Windows Applications</strong>: If you are developing for Windows systems, it is recommended to directly use the existing <code>RenderingCanvas</code> implementations in the <code>Hi.WinForm</code> or <code>Hi.WpfPlus</code> packages, rather than creating your own. These implementations are fully tested, optimized, and maintained.</p>
|
||||
<p>The implementation details provided in this document are primarily for educational purposes or for developers who need to port RenderingCanvas to other platforms/frameworks.</p>
|
||||
</div>
|
||||
<h2 id="basic-dispengine-usage">Basic DispEngine Usage</h2>
|
||||
<p>The <a class="xref" href="../../../api/Hi.Disp.DispEngine.html">DispEngine</a> is designed to display objects that implement the <a class="xref" href="../../../api/Hi.Disp.IDisplayee.html">IDisplayee</a> interface. This is the fundamental purpose of DispEngine - to render displayable objects. Assign <a class="xref" href="../../../api/Hi.Disp.IDisplayee.html">IDisplayee</a> to <a class="xref" href="../../../api/Hi.Disp.DispEngine.html">DispEngine</a>.<a class="xref" href="../../../api/Hi.Disp.DispEngine.html#Hi_Disp_DispEngine_Displayee">Displayee</a>.</p>
|
||||
<h2 id="core-implementation-pattern">Core Implementation Pattern</h2>
|
||||
<p>When implementing a custom <code>RenderingCanvas</code> for a UI platform, follow these key steps:</p>
|
||||
<ol>
|
||||
<li><strong>Initialize UI Component</strong> - Set up the UI control properties and event handling</li>
|
||||
<li><strong>Configure DispEngine</strong> - Create and properly initialize the <a class="xref" href="../../../api/Hi.Disp.DispEngine.html">DispEngine</a> instance</li>
|
||||
<li><strong>Set Up Rendering Pipeline</strong> - Implement buffer swapping mechanism for visualization</li>
|
||||
<li><strong>Handle User Input</strong> - Map platform-specific input events to DispEngine methods</li>
|
||||
<li><strong>Manage Component Lifecycle</strong> - Ensure proper resource management and cleanup</li>
|
||||
</ol>
|
||||
<p>Let's examine the actual implementations in WinForm and WPF frameworks to understand these patterns in practice.</p>
|
||||
<h2 id="winform-implementation-details">WinForm Implementation Details</h2>
|
||||
<p>The WinForm implementation in <code>Hi.WinForm</code> combines Windows Forms controls with the <a class="xref" href="../../../api/Hi.Disp.DispEngine.html">DispEngine</a> rendering system.</p>
|
||||
<h3 id="core-properties-and-fields">Core Properties and Fields</h3>
|
||||
<p>Here are the essential properties and fields defined in the WinForm implementation:</p>
|
||||
<pre><code class="lang-csharp" name="RenderingCanvas">/// <summary>
|
||||
/// <see cref="DispEngine"/>.
|
||||
/// </summary>
|
||||
public DispEngine DispEngine { get; }
|
||||
|
||||
// Constants and structures for WM_TOUCH
|
||||
private const int WM_TOUCH = 0x0240;
|
||||
private const int TOUCHEVENTF_MOVE = 0x0001;
|
||||
private const int TOUCHEVENTF_DOWN = 0x0002;
|
||||
private const int TOUCHEVENTF_UP = 0x0004;
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
private struct TOUCHINPUT
|
||||
{
|
||||
public int x;
|
||||
public int y;
|
||||
public IntPtr hSource;
|
||||
public int dwID;
|
||||
public int dwFlags;
|
||||
public int dwMask;
|
||||
public int dwTime;
|
||||
public IntPtr dwExtraInfo;
|
||||
public int cxContact;
|
||||
public int cyContact;
|
||||
}
|
||||
|
||||
[DllImport("user32.dll")]
|
||||
private static extern bool RegisterTouchWindow(IntPtr hWnd, uint ulFlags);
|
||||
|
||||
[DllImport("user32.dll")]
|
||||
private static extern bool GetTouchInputInfo(IntPtr hTouchInput, int cInputs, [In, Out] TOUCHINPUT[] pInputs, int cbSize);
|
||||
|
||||
[DllImport("user32.dll")]
|
||||
private static extern void CloseTouchInputHandle(IntPtr lParam);
|
||||
</code></pre><h3 id="initialization">Initialization</h3>
|
||||
<p>The initialization code sets up event handlers and creates the DispEngine:</p>
|
||||
<pre><code class="lang-csharp" name="RenderingCanvas">/// <summary>
|
||||
/// Ctor.
|
||||
/// </summary>
|
||||
/// <param name="displayees">displayees</param>
|
||||
public unsafe RenderingCanvas(params IDisplayee[] displayees)
|
||||
{
|
||||
// Configure the control's visual styles
|
||||
SetStyle(ControlStyles.Selectable, true);
|
||||
SetStyle(ControlStyles.OptimizedDoubleBuffer, false);
|
||||
SetStyle(ControlStyles.ContainerControl, false);
|
||||
SetStyle(ControlStyles.ResizeRedraw, false);
|
||||
DoubleBuffered = true;
|
||||
|
||||
InitializeComponent();
|
||||
Dock = DockStyle.Fill;
|
||||
|
||||
// Connect event handlers for user input and window events
|
||||
this.Resize += RenderingCanvas_Resize;
|
||||
this.VisibleChanged += RenderingCanvas_VisibleChanged;
|
||||
this.MouseMove += RenderingCanvas_MouseMove;
|
||||
this.MouseDown += RenderingCanvas_MouseDown;
|
||||
this.MouseUp += RenderingCanvas_MouseUp;
|
||||
this.MouseWheel += RenderingCanvas_MouseWheel;
|
||||
this.KeyDown += RenderingCanvas_KeyDown;
|
||||
this.KeyUp += RenderingCanvas_KeyUp;
|
||||
|
||||
// Add focus event handler
|
||||
this.GotFocus += RenderingCanvas_GotFocus;
|
||||
this.HandleCreated += OnHandleCreated;
|
||||
|
||||
// Enable touch input and click events for the control
|
||||
this.SetStyle(ControlStyles.StandardClick, true);
|
||||
this.SetStyle(ControlStyles.StandardDoubleClick, true);
|
||||
this.TabStop = true;
|
||||
|
||||
// Initialize the DispEngine with provided displayees
|
||||
DispEngine = new DispEngine(displayees);
|
||||
DispEngine.BackgroundColor = new Vec3d(0.1, 0.1, 0.5);
|
||||
DispEngine.BackgroundOpacity = 0.1;
|
||||
DispEngine.SetViewToHomeView();
|
||||
DispEngine.ImageRequestAfterBufferSwapped += DispEngine_ImageRequestAfterBufferSwapped;
|
||||
|
||||
// Set initial size and start the rendering engine
|
||||
this.Size = new System.Drawing.Size(500, 300);
|
||||
DispEngine.Start(this.ClientSize.Width, this.ClientSize.Height);
|
||||
}
|
||||
</code></pre><h3 id="rendering-pipeline">Rendering Pipeline</h3>
|
||||
<p>The rendering pipeline processes images from DispEngine and displays them:</p>
|
||||
<pre><code class="lang-csharp" name="RenderingCanvas">private unsafe void DispEngine_ImageRequestAfterBufferSwapped(byte* bgra_unsignedbyte_pixels, int w, int h)
|
||||
{
|
||||
// Create a bitmap from the raw pixel data provided by DispEngine
|
||||
Bitmap bitmap;
|
||||
bitmap = new Bitmap(new Bitmap(w, h, w * 4,
|
||||
PixelFormat.Format32bppArgb, new IntPtr(bgra_unsignedbyte_pixels)));
|
||||
|
||||
// Update the background image and dispose the previous one
|
||||
Image pre = this.BackgroundImage;
|
||||
this.BackgroundImage = bitmap;
|
||||
pre?.Dispose();
|
||||
}
|
||||
</code></pre><h3 id="input-handling">Input Handling</h3>
|
||||
<h4 id="windows-message-handling-for-touch">Windows Message Handling for Touch</h4>
|
||||
<p>WinForm implementation intercepts Windows touch messages and forwards them to DispEngine:</p>
|
||||
<pre><code class="lang-csharp" name="RenderingCanvas">/// <summary>
|
||||
/// Processes Windows messages, handling touch input and forwarding other messages to the base class.
|
||||
/// </summary>
|
||||
/// <param name="m">The Windows message to process.</param>
|
||||
protected override void WndProc(ref Message m)
|
||||
{
|
||||
if (m.Msg == WM_TOUCH)
|
||||
{
|
||||
HandleTouchInput(m.WParam, m.LParam);
|
||||
return;
|
||||
}
|
||||
|
||||
base.WndProc(ref m);
|
||||
}
|
||||
|
||||
private void OnHandleCreated(object sender, EventArgs e)
|
||||
{
|
||||
// Register window to receive touch messages
|
||||
RegisterTouchWindow(this.Handle, 0);
|
||||
}
|
||||
|
||||
private void HandleTouchInput(IntPtr wParam, IntPtr lParam)
|
||||
{
|
||||
int inputCount = wParam.ToInt32();
|
||||
TOUCHINPUT[] inputs = new TOUCHINPUT[inputCount];
|
||||
|
||||
if (!GetTouchInputInfo(lParam, inputCount, inputs, Marshal.SizeOf(typeof(TOUCHINPUT))))
|
||||
return;
|
||||
|
||||
try
|
||||
{
|
||||
for (int i = 0; i < inputCount; i++)
|
||||
{
|
||||
TOUCHINPUT ti = inputs[i];
|
||||
int touchId = ti.dwID;
|
||||
|
||||
// Convert touch coordinates to client coordinates
|
||||
Point touchPoint = PointToClient(new Point(ti.x / 100, ti.y / 100));
|
||||
|
||||
if ((ti.dwFlags & TOUCHEVENTF_DOWN) != 0)
|
||||
{
|
||||
// Touch down event
|
||||
DispEngine.TouchDown(touchId, touchPoint.X, touchPoint.Y);
|
||||
this.Focus();
|
||||
}
|
||||
else if ((ti.dwFlags & TOUCHEVENTF_MOVE) != 0)
|
||||
{
|
||||
// Touch move event
|
||||
DispEngine.TouchMove(touchId, touchPoint.X, touchPoint.Y);
|
||||
}
|
||||
else if ((ti.dwFlags & TOUCHEVENTF_UP) != 0)
|
||||
{
|
||||
// Touch up event
|
||||
DispEngine.TouchUp(touchId);
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
CloseTouchInputHandle(lParam);
|
||||
}
|
||||
}
|
||||
</code></pre>
|
||||
<p>The key aspect is mapping Windows touch events to DispEngine's touch API:</p>
|
||||
<pre><code class="lang-csharp">// Inside HandleTouchInput method
|
||||
if ((ti.dwFlags & TOUCHEVENTF_DOWN) != 0)
|
||||
{
|
||||
// Touch down event - delegate to DispEngine
|
||||
DispEngine.TouchDown(touchId, touchPoint.X, touchPoint.Y);
|
||||
this.Focus();
|
||||
}
|
||||
else if ((ti.dwFlags & TOUCHEVENTF_MOVE) != 0)
|
||||
{
|
||||
// Touch move event - delegate to DispEngine
|
||||
DispEngine.TouchMove(touchId, touchPoint.X, touchPoint.Y);
|
||||
}
|
||||
else if ((ti.dwFlags & TOUCHEVENTF_UP) != 0)
|
||||
{
|
||||
// Touch up event - delegate to DispEngine
|
||||
DispEngine.TouchUp(touchId);
|
||||
}
|
||||
</code></pre>
|
||||
<h4 id="mouse-events">Mouse Events</h4>
|
||||
<pre><code class="lang-csharp" name="RenderingCanvas">private void RenderingCanvas_MouseMove(object sender, MouseEventArgs e)
|
||||
{
|
||||
// Update mouse position and handle drag transforms
|
||||
DispEngine.MouseMove(e.Location.X, e.Location.Y);
|
||||
DispEngine.MouseDragTransform(e.Location.X, e.Location.Y,
|
||||
new mouse_button_table__transform_view_by_mouse_drag_t()
|
||||
{
|
||||
LEFT_BUTTON = (long)MouseButtons.Left,
|
||||
RIGHT_BUTTON = (long)MouseButtons.Right
|
||||
});
|
||||
}
|
||||
|
||||
private void RenderingCanvas_MouseDown(object sender, MouseEventArgs e)
|
||||
{
|
||||
// Handle mouse button press
|
||||
DispEngine.MouseButtonDown((long)e.Button);
|
||||
this.Focus();
|
||||
}
|
||||
|
||||
private void RenderingCanvas_MouseUp(object sender, MouseEventArgs e)
|
||||
{
|
||||
// Handle mouse button release
|
||||
DispEngine.MouseButtonUp((long)e.Button);
|
||||
}
|
||||
|
||||
private void RenderingCanvas_MouseWheel(object sender, MouseEventArgs e)
|
||||
{
|
||||
// Handle mouse wheel for zoom operations
|
||||
DispEngine.MouseWheel(0, e.Delta / 120);
|
||||
DispEngine.MouseWheelTransform(0, e.Delta / 120);
|
||||
}
|
||||
</code></pre><h4 id="keyboard-events">Keyboard Events</h4>
|
||||
<pre><code class="lang-csharp" name="RenderingCanvas">/// <inheritdoc/>
|
||||
protected override bool IsInputKey(Keys keyData)
|
||||
{
|
||||
//since in default, arrow does not trigger key event(keyDown and keyUp).
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Convert WinForms Keys to W3C KeyboardEvent.key string.
|
||||
/// </summary>
|
||||
static string WinFormsKeyToW3C(Keys key) => (key & Keys.KeyCode) switch
|
||||
{
|
||||
Keys.Home => "Home",
|
||||
Keys.End => "End",
|
||||
Keys.PageUp => "PageUp",
|
||||
Keys.PageDown => "PageDown",
|
||||
Keys.Left => "ArrowLeft",
|
||||
Keys.Right => "ArrowRight",
|
||||
Keys.Up => "ArrowUp",
|
||||
Keys.Down => "ArrowDown",
|
||||
Keys.LShiftKey or Keys.RShiftKey or Keys.ShiftKey => "Shift",
|
||||
Keys.LControlKey or Keys.RControlKey or Keys.ControlKey => "Control",
|
||||
Keys.LMenu or Keys.RMenu or Keys.Menu => "Alt",
|
||||
Keys.Return => "Enter",
|
||||
Keys.Escape => "Escape",
|
||||
Keys.Back => "Backspace",
|
||||
Keys.Tab => "Tab",
|
||||
Keys.Delete => "Delete",
|
||||
Keys.Insert => "Insert",
|
||||
Keys.Space => " ",
|
||||
Keys.F1 => "F1",
|
||||
Keys.F2 => "F2",
|
||||
Keys.F3 => "F3",
|
||||
Keys.F4 => "F4",
|
||||
Keys.F5 => "F5",
|
||||
Keys.F6 => "F6",
|
||||
Keys.F7 => "F7",
|
||||
Keys.F8 => "F8",
|
||||
Keys.F9 => "F9",
|
||||
Keys.F10 => "F10",
|
||||
Keys.F11 => "F11",
|
||||
Keys.F12 => "F12",
|
||||
>= Keys.A and <= Keys.Z => ((char)('a' + ((key & Keys.KeyCode) - Keys.A))).ToString(),
|
||||
>= Keys.D0 and <= Keys.D9 => ((char)('0' + ((key & Keys.KeyCode) - Keys.D0))).ToString(),
|
||||
_ => "Unidentified"
|
||||
};
|
||||
|
||||
private void RenderingCanvas_KeyDown(object sender, KeyEventArgs e)
|
||||
{
|
||||
Focus();
|
||||
string key = WinFormsKeyToW3C(e.KeyData);
|
||||
DispEngine.KeyDown(key);
|
||||
|
||||
DispEngine.KeyDownTransform(key, new key_table__transform_view_by_key_pressing_t()
|
||||
{
|
||||
HOME = "Home",
|
||||
PAGE_UP = "PageUp",
|
||||
PAGE_DOWN = "PageDown",
|
||||
F1 = "F1",
|
||||
F2 = "F2",
|
||||
F3 = "F3",
|
||||
F4 = "F4",
|
||||
SHIFT = "Shift",
|
||||
ARROW_LEFT = "ArrowLeft",
|
||||
ARROW_RIGHT = "ArrowRight",
|
||||
ARROW_DOWN = "ArrowDown",
|
||||
ARROW_UP = "ArrowUp"
|
||||
});
|
||||
}
|
||||
|
||||
private void RenderingCanvas_KeyUp(object sender, KeyEventArgs e)
|
||||
{
|
||||
DispEngine.KeyUp(WinFormsKeyToW3C(e.KeyData));
|
||||
}
|
||||
</code></pre><h3 id="lifecycle-management">Lifecycle Management</h3>
|
||||
<p>Window event handling ensures proper state management:</p>
|
||||
<pre><code class="lang-csharp" name="RenderingCanvas">private void RenderingCanvas_Resize(object sender, EventArgs e)
|
||||
{
|
||||
// Notify DispEngine of size changes
|
||||
DispEngine.Resize(this.ClientSize.Width, this.ClientSize.Height);
|
||||
}
|
||||
|
||||
private void RenderingCanvas_VisibleChanged(object sender, EventArgs e)
|
||||
{
|
||||
// Update visibility state in DispEngine
|
||||
DispEngine.IsVisible = this.Visible;
|
||||
}
|
||||
</code></pre><h3 id="resource-cleanup">Resource Cleanup</h3>
|
||||
<pre><code class="lang-csharp" name="RenderingCanvas">/// <summary>
|
||||
/// Clean up any resources being used.
|
||||
/// </summary>
|
||||
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing && (components != null))
|
||||
{
|
||||
// Dispose the DispEngine to free resources
|
||||
DispEngine.Dispose();
|
||||
components.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
</code></pre><h2 id="wpf-implementation-details">WPF Implementation Details</h2>
|
||||
<p>The WPF implementation uses WPF-specific controls and mechanisms but follows the same core pattern.</p>
|
||||
<h3 id="core-properties">Core Properties</h3>
|
||||
<pre><code class="lang-csharp" name="RenderingCanvas">/// <summary>
|
||||
/// The DispEngine instance that handles rendering and user interactions
|
||||
/// </summary>
|
||||
public DispEngine DispEngine { get; } = new DispEngine();
|
||||
|
||||
/// <summary>
|
||||
/// Internal container for rendering content
|
||||
/// </summary>
|
||||
private UserControl DisplayerPane { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Dictionary to store touch point information
|
||||
/// </summary>
|
||||
private Dictionary<int, Point> TouchingPointsMap { get; } = new Dictionary<int, Point>();
|
||||
|
||||
/// <summary>
|
||||
/// Dictionary to store previous positions of touch points
|
||||
/// </summary>
|
||||
private Dictionary<int, Point> PreviousTouchingPointsMap { get; } = new Dictionary<int, Point>();
|
||||
</code></pre><h3 id="initialization-1">Initialization</h3>
|
||||
<pre><code class="lang-csharp" name="RenderingCanvas">/// <summary>
|
||||
/// Initializes a new instance of the RenderingCanvas
|
||||
/// </summary>
|
||||
public RenderingCanvas()
|
||||
{
|
||||
DispEngine.BackgroundColor = new Vec3d(0.1, 0.1, 0.5);
|
||||
DispEngine.BackgroundOpacity = 0.1;
|
||||
|
||||
// Configure the main control properties
|
||||
HorizontalAlignment = HorizontalAlignment.Stretch;
|
||||
VerticalAlignment = VerticalAlignment.Stretch;
|
||||
Focusable = true;
|
||||
KeyboardNavigation.SetDirectionalNavigation(this, KeyboardNavigationMode.Cycle);
|
||||
DataContextChanged += CanvasDataContextChanged;
|
||||
|
||||
// Create and configure the display pane
|
||||
DisplayerPane = new UserControl();
|
||||
DisplayerPane.HorizontalAlignment = HorizontalAlignment.Stretch;
|
||||
DisplayerPane.VerticalAlignment = VerticalAlignment.Stretch;
|
||||
DisplayerPane.Focusable = true;
|
||||
DisplayerPane.IsTabStop = true;
|
||||
|
||||
// Connect event handlers for user input and window events
|
||||
DisplayerPane.SizeChanged += RenderingCanvas_SizeChanged;
|
||||
DisplayerPane.MouseMove += RenderingCanvas_MouseMove;
|
||||
DisplayerPane.MouseDown += RenderingCanvas_MouseDown;
|
||||
DisplayerPane.MouseUp += RenderingCanvas_MouseUp;
|
||||
DisplayerPane.MouseWheel += RenderingCanvas_MouseWheel;
|
||||
DisplayerPane.KeyDown += RenderingCanvas_KeyDown;
|
||||
DisplayerPane.KeyUp += RenderingCanvas_KeyUp;
|
||||
DisplayerPane.Loaded += RenderingCanvas_Loaded;
|
||||
DisplayerPane.Unloaded += RenderingCanvas_Unloaded;
|
||||
DisplayerPane.IsVisibleChanged += DisplayerPane_IsVisibleChanged;
|
||||
|
||||
// Add touch event handlers
|
||||
DisplayerPane.TouchDown += RenderingCanvas_TouchDown;
|
||||
DisplayerPane.TouchMove += RenderingCanvas_TouchMove;
|
||||
DisplayerPane.TouchUp += RenderingCanvas_TouchUp;
|
||||
|
||||
// Enable touch support
|
||||
this.IsManipulationEnabled = true;
|
||||
|
||||
// Initialize power management
|
||||
InitializePowerManagement();
|
||||
|
||||
// Add the display pane to this control's content
|
||||
Content = DisplayerPane;
|
||||
}
|
||||
</code></pre><h3 id="rendering-pipeline-1">Rendering Pipeline</h3>
|
||||
<pre><code class="lang-csharp" name="RenderingCanvas">/// <summary>
|
||||
/// Handles the buffer swapped event from DispEngine
|
||||
/// </summary>
|
||||
private unsafe void RenderingCanvas_BufferSwapped(byte* data, int w, int h)
|
||||
{
|
||||
if (data == null)
|
||||
return;
|
||||
|
||||
Span<byte> bgra = new Span<byte>(data, w * h * 4);
|
||||
|
||||
// Copy pixel data from DispEngine
|
||||
int n = w * h * 4;
|
||||
byte[] arr = new byte[n];
|
||||
for (int i = 0; i < n; i++)
|
||||
arr[i] = data[i];
|
||||
|
||||
// Update UI on the UI thread
|
||||
DisplayerPane.Dispatcher.InvokeAsync(() =>
|
||||
{
|
||||
BitmapSource bitmap = BitmapSource.Create(w, h, 1, 1, PixelFormats.Bgra32, null, arr, w * 4);
|
||||
DisplayerPane.Background = new ImageBrush(bitmap);
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handles the size changed event
|
||||
/// </summary>
|
||||
private void RenderingCanvas_SizeChanged(object sender, SizeChangedEventArgs e)
|
||||
{
|
||||
// Notify DispEngine of size changes
|
||||
DispEngine.Resize((int)DisplayerPane.RenderSize.Width, (int)DisplayerPane.RenderSize.Height);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handles visibility changes
|
||||
/// </summary>
|
||||
private unsafe void DisplayerPane_IsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
// Update visibility state in DispEngine
|
||||
DispEngine.IsVisible = IsVisible;
|
||||
}
|
||||
</code></pre><h3 id="mouse-and-keyboard-handling">Mouse and Keyboard Handling</h3>
|
||||
<pre><code class="lang-csharp" name="RenderingCanvas">/// <summary>
|
||||
/// Helper method to get mouse button mask
|
||||
/// </summary>
|
||||
internal static HiMouseButtonMask GetMouseButtonMask(MouseDevice device)
|
||||
{
|
||||
HiMouseButtonMask mouseButtonMask = 0;
|
||||
mouseButtonMask.SetLeftPressed(device.LeftButton == MouseButtonState.Pressed);
|
||||
mouseButtonMask.SetMiddlePressed(device.MiddleButton == MouseButtonState.Pressed);
|
||||
mouseButtonMask.SetRightPressed(device.RightButton == MouseButtonState.Pressed);
|
||||
mouseButtonMask.SetXButton1Pressed(device.XButton1 == MouseButtonState.Pressed);
|
||||
mouseButtonMask.SetXButton2Pressed(device.XButton2 == MouseButtonState.Pressed);
|
||||
return mouseButtonMask;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handles the mouse wheel event
|
||||
/// </summary>
|
||||
private void RenderingCanvas_MouseWheel(object sender, MouseWheelEventArgs e)
|
||||
{
|
||||
// Handle mouse wheel for zoom operations
|
||||
DispEngine.MouseWheel(0, e.Delta / 120);
|
||||
DispEngine.MouseWheelTransform(0, e.Delta / 120);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handles the mouse up event
|
||||
/// </summary>
|
||||
private void RenderingCanvas_MouseUp(object sender, MouseButtonEventArgs e)
|
||||
{
|
||||
// Handle mouse button release
|
||||
DispEngine.MouseButtonUp((long)e.ChangedButton);
|
||||
(sender as UIElement)?.ReleaseMouseCapture();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handles the mouse down event
|
||||
/// </summary>
|
||||
private void RenderingCanvas_MouseDown(object sender, MouseButtonEventArgs e)
|
||||
{
|
||||
// Handle mouse button press
|
||||
DispEngine.MouseButtonDown((long)e.ChangedButton);
|
||||
DisplayerPane.Focus();
|
||||
(sender as UIElement)?.CaptureMouse();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handles the mouse move event
|
||||
/// </summary>
|
||||
private void RenderingCanvas_MouseMove(object sender, MouseEventArgs e)
|
||||
{
|
||||
// Update mouse position and handle drag transforms
|
||||
Point p = e.GetPosition(DisplayerPane);
|
||||
DispEngine.MouseMove((int)p.X, (int)p.Y);
|
||||
DispEngine.MouseDragTransform((int)p.X, (int)p.Y,
|
||||
new mouse_button_table__transform_view_by_mouse_drag_t()
|
||||
{
|
||||
LEFT_BUTTON = (long)MouseButton.Left,
|
||||
RIGHT_BUTTON = (long)MouseButton.Right
|
||||
});
|
||||
}
|
||||
</code></pre><pre><code class="lang-csharp" name="RenderingCanvas">/// <summary>
|
||||
/// Convert WPF Key to W3C KeyboardEvent.key string.
|
||||
/// </summary>
|
||||
static string WpfKeyToW3C(Key key) => key switch
|
||||
{
|
||||
Key.Home => "Home",
|
||||
Key.End => "End",
|
||||
Key.PageUp => "PageUp",
|
||||
Key.PageDown => "PageDown",
|
||||
Key.Left => "ArrowLeft",
|
||||
Key.Right => "ArrowRight",
|
||||
Key.Up => "ArrowUp",
|
||||
Key.Down => "ArrowDown",
|
||||
Key.LeftShift or Key.RightShift => "Shift",
|
||||
Key.LeftCtrl or Key.RightCtrl => "Control",
|
||||
Key.LeftAlt or Key.RightAlt => "Alt",
|
||||
Key.Return => "Enter",
|
||||
Key.Escape => "Escape",
|
||||
Key.Back => "Backspace",
|
||||
Key.Tab => "Tab",
|
||||
Key.Delete => "Delete",
|
||||
Key.Insert => "Insert",
|
||||
Key.Space => " ",
|
||||
Key.F1 => "F1",
|
||||
Key.F2 => "F2",
|
||||
Key.F3 => "F3",
|
||||
Key.F4 => "F4",
|
||||
Key.F5 => "F5",
|
||||
Key.F6 => "F6",
|
||||
Key.F7 => "F7",
|
||||
Key.F8 => "F8",
|
||||
Key.F9 => "F9",
|
||||
Key.F10 => "F10",
|
||||
Key.F11 => "F11",
|
||||
Key.F12 => "F12",
|
||||
>= Key.A and <= Key.Z => ((char)('a' + (key - Key.A))).ToString(),
|
||||
>= Key.D0 and <= Key.D9 => ((char)('0' + (key - Key.D0))).ToString(),
|
||||
_ => "Unidentified"
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Handles the key up event
|
||||
/// </summary>
|
||||
private void RenderingCanvas_KeyUp(object sender, KeyEventArgs e)
|
||||
{
|
||||
DispEngine.KeyUp(WpfKeyToW3C(e.Key));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handles the key down event
|
||||
/// </summary>
|
||||
private void RenderingCanvas_KeyDown(object sender, KeyEventArgs e)
|
||||
{
|
||||
string key = WpfKeyToW3C(e.Key);
|
||||
DispEngine.KeyDown(key);
|
||||
|
||||
DispEngine.KeyDownTransform(key, new key_table__transform_view_by_key_pressing_t()
|
||||
{
|
||||
HOME = "Home",
|
||||
PAGE_UP = "PageUp",
|
||||
PAGE_DOWN = "PageDown",
|
||||
F1 = "F1",
|
||||
F2 = "F2",
|
||||
F3 = "F3",
|
||||
F4 = "F4",
|
||||
SHIFT = "Shift",
|
||||
ARROW_LEFT = "ArrowLeft",
|
||||
ARROW_RIGHT = "ArrowRight",
|
||||
ARROW_DOWN = "ArrowDown",
|
||||
ARROW_UP = "ArrowUp"
|
||||
});
|
||||
}
|
||||
</code></pre><h3 id="lifecycle-management-1">Lifecycle Management</h3>
|
||||
<pre><code class="lang-csharp" name="RenderingCanvas">/// <summary>
|
||||
/// Handles window state changes (maximize, minimize, etc.)
|
||||
/// </summary>
|
||||
private unsafe void RenderingCanvas_StateChanged(object sender, EventArgs e)
|
||||
{
|
||||
switch ((sender as Window).WindowState)
|
||||
{
|
||||
case WindowState.Maximized:
|
||||
DispEngine.IsVisible = true;
|
||||
break;
|
||||
case WindowState.Minimized:
|
||||
DispEngine.IsVisible = false;
|
||||
break;
|
||||
case WindowState.Normal:
|
||||
DispEngine.IsVisible = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handles data context changes
|
||||
/// </summary>
|
||||
private unsafe void CanvasDataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
DispEngine pre = e.OldValue as DispEngine;
|
||||
DispEngine cur = e.NewValue as DispEngine;
|
||||
|
||||
//child's binding event is triggered after IsVisible event and Load event.
|
||||
if (pre != null) //this section will never occur if the datacontext not set twice.
|
||||
{
|
||||
pre.Terminate();
|
||||
pre.ImageRequestAfterBufferSwapped -= RenderingCanvas_BufferSwapped;
|
||||
}
|
||||
if (cur != null)
|
||||
{
|
||||
cur.ImageRequestAfterBufferSwapped += RenderingCanvas_BufferSwapped;
|
||||
cur.Start((int)DisplayerPane.RenderSize.Width, (int)DisplayerPane.RenderSize.Height);
|
||||
|
||||
cur.IsVisible = IsVisible;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reference to the current window containing this control
|
||||
/// </summary>
|
||||
private Window currentWindow;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the current window, connecting or disconnecting state change events
|
||||
/// </summary>
|
||||
Window CurrentWindow
|
||||
{
|
||||
get => currentWindow; set
|
||||
{
|
||||
if (currentWindow != null)
|
||||
currentWindow.StateChanged -= RenderingCanvas_StateChanged;
|
||||
currentWindow = value;
|
||||
if (currentWindow != null)
|
||||
currentWindow.StateChanged += RenderingCanvas_StateChanged;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handles the loaded event
|
||||
/// </summary>
|
||||
private unsafe void RenderingCanvas_Loaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
// Get the window containing this control
|
||||
CurrentWindow = Window.GetWindow(this);
|
||||
|
||||
// Set up DispEngine rendering
|
||||
DispEngine.ImageRequestAfterBufferSwapped -= RenderingCanvas_BufferSwapped;
|
||||
DispEngine.ImageRequestAfterBufferSwapped += RenderingCanvas_BufferSwapped;
|
||||
DispEngine.Start((int)DisplayerPane.RenderSize.Width, (int)DisplayerPane.RenderSize.Height);
|
||||
DispEngine.IsVisible = IsVisible;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handles the unloaded event
|
||||
/// </summary>
|
||||
private unsafe void RenderingCanvas_Unloaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
DispEngine.IsVisible = IsVisible;
|
||||
DispEngine.ImageRequestAfterBufferSwapped -= RenderingCanvas_BufferSwapped;
|
||||
CurrentWindow = null;
|
||||
}
|
||||
</code></pre><h3 id="resource-cleanup-1">Resource Cleanup</h3>
|
||||
<pre><code class="lang-csharp" name="RenderingCanvas">/// <summary>
|
||||
/// Flag to track disposed state
|
||||
/// </summary>
|
||||
private bool disposedValue;
|
||||
|
||||
/// <summary>
|
||||
/// Disposes managed resources
|
||||
/// </summary>
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (!disposedValue)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
// Unsubscribe from power events
|
||||
SystemEvents.PowerModeChanged -= SystemEvents_PowerModeChanged;
|
||||
|
||||
// Dispose the DispEngine to free resources
|
||||
DispEngine.Dispose();
|
||||
}
|
||||
disposedValue = true;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Public dispose method to free resources
|
||||
/// </summary>
|
||||
public void Dispose()
|
||||
{
|
||||
// Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
|
||||
Dispose(disposing: true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
</code></pre><h2 id="core-dispengine-integration-patterns">Core DispEngine Integration Patterns</h2>
|
||||
<h3 id="1-initialization-sequence">1. Initialization Sequence</h3>
|
||||
<pre><code class="lang-csharp">// Create DispEngine (optionally with displayees)
|
||||
var engine = new DispEngine(displayees);
|
||||
|
||||
// Set up image buffer callback
|
||||
engine.ImageRequestAfterBufferSwapped += OnBufferSwapped;
|
||||
|
||||
// Initialize with canvas size
|
||||
engine.Start(width, height);
|
||||
|
||||
// Set initial view (optional)
|
||||
engine.SetViewToHomeView();
|
||||
</code></pre>
|
||||
<h3 id="2-render-loop">2. Render Loop</h3>
|
||||
<p>The rendering process follows this pattern:</p>
|
||||
<ol>
|
||||
<li><a class="xref" href="../../../api/Hi.Disp.DispEngine.html">DispEngine</a> processes <a class="xref" href="../../../api/Hi.Disp.IDisplayee.html">IDisplayee</a> objects</li>
|
||||
<li>Buffer is swapped and callback is triggered</li>
|
||||
<li>UI framework renders the buffer to screen</li>
|
||||
<li>User input triggers view updates</li>
|
||||
<li>Process repeats</li>
|
||||
</ol>
|
||||
<h3 id="3-complete-user-input-mapping">3. Complete User Input Mapping</h3>
|
||||
<p>All user interactions must be mapped to <a class="xref" href="../../../api/Hi.Disp.DispEngine.html">DispEngine</a> methods:</p>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>User Action</th>
|
||||
<th>DispEngine Method</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>Mouse move</td>
|
||||
<td><a class="xref" href="../../../api/Hi.Disp.DispEngine.html#Hi_Disp_DispEngine_MouseMove_System_Int32_System_Int32_">MouseMove(int, int)</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Mouse drag</td>
|
||||
<td><a class="xref" href="../../../api/Hi.Disp.DispEngine.html#Hi_Disp_DispEngine_MouseDragTransform_System_Int32_System_Int32_Hi_Native_mouse_button_table__transform_view_by_mouse_drag_t_">MouseDragTransform(int, int, mouse_button_table__transform_view_by_mouse_drag_t)</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Mouse button</td>
|
||||
<td><a class="xref" href="../../../api/Hi.Disp.DispEngine.html#Hi_Disp_DispEngine_MouseButtonDown_System_Int64_">MouseButtonDown(long)</a> / <a class="xref" href="../../../api/Hi.Disp.DispEngine.html#Hi_Disp_DispEngine_MouseButtonUp_System_Int64_">MouseButtonUp(long)</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Mouse wheel</td>
|
||||
<td><a class="xref" href="../../../api/Hi.Disp.DispEngine.html#Hi_Disp_DispEngine_MouseWheel_System_Int32_System_Int32_">MouseWheel(int, int)</a> and <a class="xref" href="../../../api/Hi.Disp.DispEngine.html#Hi_Disp_DispEngine_MouseWheelTransform_System_Int32_System_Int32_System_Double_">MouseWheelTransform(int, int, double)</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Key press</td>
|
||||
<td><a class="xref" href="../../../api/Hi.Disp.DispEngine.html#Hi_Disp_DispEngine_KeyDown_System_String_">KeyDown(string)</a> / <a class="xref" href="../../../api/Hi.Disp.DispEngine.html#Hi_Disp_DispEngine_KeyUp_System_String_">KeyUp(string)</a> and <a class="xref" href="../../../api/Hi.Disp.DispEngine.html#Hi_Disp_DispEngine_KeyDownTransform_System_String_Hi_Native_key_table__transform_view_by_key_pressing_t_">KeyDownTransform(string, key_table__transform_view_by_key_pressing_t)</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Touch events</td>
|
||||
<td><a class="xref" href="../../../api/Hi.Disp.DispEngine.html#Hi_Disp_DispEngine_TouchDown_System_Int32_System_Int32_System_Int32_">TouchDown(int, int, int)</a> / <a class="xref" href="../../../api/Hi.Disp.DispEngine.html#Hi_Disp_DispEngine_TouchMove_System_Int32_System_Int32_System_Int32_">TouchMove(int, int, int)</a> / <a class="xref" href="../../../api/Hi.Disp.DispEngine.html#Hi_Disp_DispEngine_TouchUp_System_Int32_">TouchUp(int)</a></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<h3 id="4-proper-resource-cleanup">4. Proper Resource Cleanup</h3>
|
||||
<p>Resource management is critical for proper operation:</p>
|
||||
<pre><code class="lang-csharp">// In dispose method
|
||||
DispEngine.ImageRequestAfterBufferSwapped -= OnBufferSwapped;
|
||||
DispEngine.Terminate();
|
||||
DispEngine.Dispose();
|
||||
</code></pre>
|
||||
<h2 id="advanced-implementation-considerations">Advanced Implementation Considerations</h2>
|
||||
<p>When creating custom implementations, consider these aspects:</p>
|
||||
<h3 id="view-manipulation">View Manipulation</h3>
|
||||
<p>Use <a class="xref" href="../../../api/Hi.Disp.DispEngine.html#Hi_Disp_DispEngine_SketchView">SketchView</a> to directly access or modify the view matrix:</p>
|
||||
<pre><code class="lang-csharp">// Get current view matrix
|
||||
Mat4d currentView = engine.SketchView;
|
||||
|
||||
// Apply custom rotation
|
||||
Mat4d rotation = Mat4d.RotateX(Math.PI/4);
|
||||
engine.SketchView = currentView * rotation;
|
||||
</code></pre>
|
||||
<h2 id="see-also">See Also</h2>
|
||||
<ul>
|
||||
<li><a class="xref" href="../../../api/Hi.Disp.DispEngine.html">DispEngine</a></li>
|
||||
<li><a class="xref" href="../../../api/Hi.Disp.IDisplayee.html">IDisplayee</a></li>
|
||||
<li><a class="xref" href="../../../api/Hi.Geom.Vec2d.html">Vec2d</a></li>
|
||||
<li><a class="xref" href="../../../api/Hi.Geom.Mat4d.html">Mat4d</a></li>
|
||||
</ul>
|
||||
|
||||
</article>
|
||||
|
||||
<div class="contribution d-print-none">
|
||||
</div>
|
||||
|
||||
<div class="next-article d-print-none border-top" id="nextArticle"></div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="affix">
|
||||
<nav id="affix"></nav>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<div class="container-xxl search-results" id="search-results"></div>
|
||||
|
||||
<footer class="border-top text-secondary">
|
||||
<div class="container-xxl">
|
||||
<div class="flex-fill">
|
||||
<span> Copyright © 2025 <a href='https://superhightech.com.tw'>Tech Coordinate</a>. All rights reserved. <a href='https://superhightech.com.tw'>超級高科技股份有限公司</a> © 2025 版權所有 </span>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,265 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Using RenderingCanvas with DispEngine | HiAPI-C# 2025 </title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="title" content="Using RenderingCanvas with DispEngine | HiAPI-C# 2025 ">
|
||||
|
||||
|
||||
<link rel="icon" href="../../../img/HiAPI.favicon.ico">
|
||||
<link rel="stylesheet" href="../../../public/docfx.min.css">
|
||||
<link rel="stylesheet" href="../../../public/main.css">
|
||||
<meta name="docfx:navrel" content="../../../toc.html">
|
||||
<meta name="docfx:tocrel" content="../../toc.html">
|
||||
|
||||
<meta name="docfx:rel" content="../../../">
|
||||
|
||||
|
||||
|
||||
<meta name="loc:inThisArticle" content="In this article">
|
||||
<meta name="loc:searchResultsCount" content="{count} results for "{query}"">
|
||||
<meta name="loc:searchNoResults" content="No results for "{query}"">
|
||||
<meta name="loc:tocFilter" content="Filter by title">
|
||||
<meta name="loc:nextArticle" content="Next">
|
||||
<meta name="loc:prevArticle" content="Previous">
|
||||
<meta name="loc:themeLight" content="Light">
|
||||
<meta name="loc:themeDark" content="Dark">
|
||||
<meta name="loc:themeAuto" content="Auto">
|
||||
<meta name="loc:changeTheme" content="Change theme">
|
||||
<meta name="loc:copy" content="Copy">
|
||||
<meta name="loc:downloadPdf" content="Download PDF">
|
||||
|
||||
<script type="module" src="./../../../public/docfx.min.js"></script>
|
||||
|
||||
<script>
|
||||
const theme = localStorage.getItem('theme') || 'auto'
|
||||
document.documentElement.setAttribute('data-bs-theme', theme === 'auto' ? (window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light') : theme)
|
||||
</script>
|
||||
|
||||
</head>
|
||||
|
||||
<body class="tex2jax_ignore" data-layout="" data-yaml-mime="">
|
||||
<header class="bg-body border-bottom">
|
||||
<nav id="autocollapse" class="navbar navbar-expand-md" role="navigation">
|
||||
<div class="container-xxl flex-nowrap">
|
||||
<a class="navbar-brand" href="../../../index.html">
|
||||
<img id="logo" class="svg" src="../../../img/HiAPI.logo.png" alt="">
|
||||
|
||||
</a>
|
||||
<button class="btn btn-lg d-md-none border-0" type="button" data-bs-toggle="collapse" data-bs-target="#navpanel" aria-controls="navpanel" aria-expanded="false" aria-label="Toggle navigation">
|
||||
<i class="bi bi-three-dots"></i>
|
||||
</button>
|
||||
<div class="collapse navbar-collapse" id="navpanel">
|
||||
<div id="navbar">
|
||||
<form class="search" role="search" id="search">
|
||||
<i class="bi bi-search"></i>
|
||||
<input class="form-control" id="search-query" type="search" disabled placeholder="Search" autocomplete="off" aria-label="Search">
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
</header>
|
||||
|
||||
<main class="container-xxl">
|
||||
<div class="toc-offcanvas">
|
||||
<div class="offcanvas-md offcanvas-start" tabindex="-1" id="tocOffcanvas" aria-labelledby="tocOffcanvasLabel">
|
||||
<div class="offcanvas-header">
|
||||
<h5 class="offcanvas-title" id="tocOffcanvasLabel">Table of Contents</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="offcanvas" data-bs-target="#tocOffcanvas" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="offcanvas-body">
|
||||
<nav class="toc" id="toc"></nav>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="content">
|
||||
<div class="actionbar">
|
||||
<button class="btn btn-lg border-0 d-md-none" type="button" data-bs-toggle="offcanvas" data-bs-target="#tocOffcanvas" aria-controls="tocOffcanvas" aria-expanded="false" aria-label="Show table of contents">
|
||||
<i class="bi bi-list"></i>
|
||||
</button>
|
||||
|
||||
<nav id="breadcrumb"></nav>
|
||||
</div>
|
||||
|
||||
<article data-uid="">
|
||||
<h1 id="using-renderingcanvas-with-dispengine">Using RenderingCanvas with DispEngine</h1>
|
||||
|
||||
<p>The <code>RenderingCanvas</code> is the primary UI component for displaying and interacting with 3D content across different platforms. This section explains how to use it with the <a class="xref" href="../../../api/Hi.Disp.DispEngine.html">DispEngine</a> to create cross-platform applications.</p>
|
||||
<h2 id="overview">Overview</h2>
|
||||
<p>The <code>RenderingCanvas</code> class is available in frameworks:</p>
|
||||
<ul>
|
||||
<li><code>Hi.WinForm</code> for Windows Forms applications</li>
|
||||
<li><code>Hi.WpfPlus</code> for WPF applications</li>
|
||||
</ul>
|
||||
<p>All implementations share a common architecture centered around the <a class="xref" href="../../../api/Hi.Disp.DispEngine.html">DispEngine</a> class, enabling consistent rendering and interaction across platforms.</p>
|
||||
<h2 id="core-concept-dispengine-and-idisplayee">Core Concept: DispEngine and IDisplayee</h2>
|
||||
<p>At the heart of the rendering system is the relationship between <a class="xref" href="../../../api/Hi.Disp.DispEngine.html">DispEngine</a> and <a class="xref" href="../../../api/Hi.Disp.IDisplayee.html">IDisplayee</a>:</p>
|
||||
<ul>
|
||||
<li><a class="xref" href="../../../api/Hi.Disp.DispEngine.html">DispEngine</a>: The rendering engine that manages the OpenGL context and handles user interaction</li>
|
||||
<li><a class="xref" href="../../../api/Hi.Disp.IDisplayee.html">IDisplayee</a>: The interface that defines objects that can be rendered by the DispEngine</li>
|
||||
</ul>
|
||||
<p>This relationship is fundamental - <strong>the purpose of <a class="xref" href="../../../api/Hi.Disp.DispEngine.html">DispEngine</a> is to render <a class="xref" href="../../../api/Hi.Disp.IDisplayee.html">IDisplayee</a> objects</strong>.</p>
|
||||
<pre><code class="lang-mermaid">graph TD
|
||||
A[IDisplayee Objects] -->|Rendered by| B
|
||||
B[DispEngine] <--> C[RenderingCanvas UI Component]
|
||||
</code></pre>
|
||||
<h3 id="working-with-idisplayee">Working with IDisplayee</h3>
|
||||
<p>Objects implementing <a class="xref" href="../../../api/Hi.Disp.IDisplayee.html">IDisplayee</a> define what gets rendered. Typically, you'll use <a class="xref" href="../../../api/Hi.Disp.Drawing.html">Drawing</a> objects or compose multiple IDisplayee objects together:</p>
|
||||
<pre><code class="lang-csharp">// Create a composite displayee
|
||||
public class MyCompositeDisplayee : IDisplayee
|
||||
{
|
||||
private List<IDisplayee> _displayees = new List<IDisplayee>();
|
||||
|
||||
public MyCompositeDisplayee()
|
||||
{
|
||||
// Add various displayees
|
||||
_displayees.Add(new AxesDisplayee());
|
||||
_displayees.Add(new ModelDisplayee());
|
||||
}
|
||||
|
||||
public void Display(Bind bind)
|
||||
{
|
||||
// Render all contained displayees
|
||||
foreach (var displayee in _displayees)
|
||||
{
|
||||
displayee.Display(bind);
|
||||
}
|
||||
}
|
||||
|
||||
public void ExpandToBox3d(Box3d box)
|
||||
{
|
||||
// Update bounding box based on all displayees
|
||||
foreach (var displayee in _displayees)
|
||||
{
|
||||
displayee.ExpandToBox3d(box);
|
||||
}
|
||||
}
|
||||
}
|
||||
</code></pre>
|
||||
<p>For more detailed information on creating displayees with <a class="xref" href="../../../api/Hi.Disp.Drawing.html">Drawing</a>, see the <a href="../drawing/index.html">Drawing</a> section.</p>
|
||||
<h2 id="basic-usage">Basic Usage</h2>
|
||||
<h3 id="apply-hiwinform">Apply Hi.WinForm</h3>
|
||||
<pre><code class="lang-csharp">// Create a new instance with displayee objects
|
||||
using Hi.WinForm.Disp;
|
||||
|
||||
// Create displayee object
|
||||
var displayee = new MyCompositeDisplayee();
|
||||
|
||||
// Initialize canvas with the displayee
|
||||
var canvas = new RenderingCanvas(displayee);
|
||||
|
||||
// Access the DispEngine for direct manipulation
|
||||
DispEngine engine = canvas.DispEngine;
|
||||
|
||||
// Add to a form
|
||||
myForm.Controls.Add(canvas);
|
||||
</code></pre>
|
||||
<h3 id="apply-hiwpf">Apply Hi.WPF</h3>
|
||||
<pre><code class="lang-csharp">// Create a new instance
|
||||
using Hi.WpfPlus.Disp;
|
||||
|
||||
// Create displayee object
|
||||
var displayee = new MyCompositeDisplayee();
|
||||
|
||||
// Initialize the canvas
|
||||
var canvas = new RenderingCanvas();
|
||||
|
||||
// Set displayee objects through the DispEngine
|
||||
canvas.DispEngine.Displayee = displayee;
|
||||
|
||||
// Add to a container
|
||||
myGrid.Children.Add(canvas);
|
||||
</code></pre>
|
||||
<h2 id="switching-displayees-at-runtime">Switching Displayees at Runtime</h2>
|
||||
<p>You can dynamically change what's being displayed:</p>
|
||||
<pre><code class="lang-csharp">// Switch to a different displayee
|
||||
renderingCanvas.DispEngine.Displayee = alternativeDisplayee;
|
||||
|
||||
// Or update a DispList
|
||||
var displayList = new DispList();
|
||||
if (showModel) displayList.Add(modelDisplayee);
|
||||
if (showGrid) displayList.Add(gridDisplayee);
|
||||
renderingCanvas.DispEngine.Displayee = displayList;
|
||||
</code></pre>
|
||||
<h2 id="key-features-of-dispengine">Key Features of DispEngine</h2>
|
||||
<p>The <a class="xref" href="../../../api/Hi.Disp.DispEngine.html">DispEngine</a> provides cross-platform support for:</p>
|
||||
<ul>
|
||||
<li>Handles buffer swapping and image generation</li>
|
||||
<li>Mouse/pointer events</li>
|
||||
<li>Keyboard navigation</li>
|
||||
<li>Touch gestures</li>
|
||||
<li>Zoom, pan, and rotate operations</li>
|
||||
<li>Resize and Visibility changed.</li>
|
||||
<li>Camera positioning and orientation</li>
|
||||
<li>Standard views (front, top, isometric, etc.)</li>
|
||||
<li>Renders <a class="xref" href="../../../api/Hi.Disp.IDisplayee.html">IDisplayee</a> implementations</li>
|
||||
</ul>
|
||||
<h2 id="touch-and-gesture-support">Touch and Gesture Support</h2>
|
||||
<p>The <a class="xref" href="../../../api/Hi.Disp.DispEngine.html">DispEngine</a> centralizes touch handling across all platforms with a unified API that supports:</p>
|
||||
<ul>
|
||||
<li>Single-finger pan</li>
|
||||
<li>Two-finger rotate and scale</li>
|
||||
<li>Multi-finger specialized operations</li>
|
||||
</ul>
|
||||
<p>The touch API is designed to be simple for UI implementations to use. Platform-specific UI components only need to capture touch events and forward them to the DispEngine.</p>
|
||||
<h2 id="common-operations">Common Operations</h2>
|
||||
<pre><code class="lang-csharp">// Accessing DispEngine (works on all platforms)
|
||||
var engine = renderingCanvas.DispEngine;
|
||||
|
||||
// Set to standard views
|
||||
engine.SetViewToHomeView();
|
||||
engine.SetViewToFrontView();
|
||||
|
||||
// Manual camera manipulation
|
||||
engine.Translate(dx, dy);
|
||||
engine.Rotate(deltaX, deltaY);
|
||||
|
||||
// Resize handling
|
||||
engine.Resize(width, height);
|
||||
</code></pre>
|
||||
<h2 id="implementation-details">Implementation Details</h2>
|
||||
<p>For detailed implementation information, including:</p>
|
||||
<ul>
|
||||
<li>Full source code examples</li>
|
||||
<li>Implementation details for each platform</li>
|
||||
<li>Advanced touch handling</li>
|
||||
<li>Custom implementation guidance</li>
|
||||
</ul>
|
||||
<p>See the <a href="custom-implementation.html">Building Your Own RenderingCanvas</a> guide.</p>
|
||||
<h2 id="see-also">See Also</h2>
|
||||
<ul>
|
||||
<li><a class="xref" href="../../../api/Hi.Disp.DispEngine.html">DispEngine</a></li>
|
||||
<li><a class="xref" href="../../../api/Hi.Disp.IDisplayee.html">IDisplayee</a></li>
|
||||
<li><a class="xref" href="../../../api/Hi.Disp.DispList.html">DispList</a></li>
|
||||
<li><a class="xref" href="../../../api/Hi.Disp.Drawing.html">Drawing</a></li>
|
||||
<li><a href="custom-implementation.html">Building Your Own RenderingCanvas</a></li>
|
||||
</ul>
|
||||
|
||||
</article>
|
||||
|
||||
<div class="contribution d-print-none">
|
||||
</div>
|
||||
|
||||
<div class="next-article d-print-none border-top" id="nextArticle"></div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="affix">
|
||||
<nav id="affix"></nav>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<div class="container-xxl search-results" id="search-results"></div>
|
||||
|
||||
<footer class="border-top text-secondary">
|
||||
<div class="container-xxl">
|
||||
<div class="flex-fill">
|
||||
<span> Copyright © 2025 <a href='https://superhightech.com.tw'>Tech Coordinate</a>. All rights reserved. <a href='https://superhightech.com.tw'>超級高科技股份有限公司</a> © 2025 版權所有 </span>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user