sincerely Singaporean

If you have not done so, read this full tutorial on how to use SGEXTN to build an application.

Full Tutorial Part 18

See here for the previous part of the tutorial.

In the previous part, we built the polygon display.

shaders (part 3)

Next we will be building the star display. Similar to how we built the polygon display, we will define the shape of the star using actual vertices stored in the vertex buffer object. The coordinate system used by the vertices will be the same as those of the polygon, so we can reuse the same vertex and fragment shaders. We will use a SGWBlankWidget for the background.

At this point, you have already implemented 2 shaders, 1 for the circle and 1 for the polygon. You can try to entirely implement this by yourself. The location of the vertices can be easily determined using trigonometry and geometry from lower secondary mathematics.

In case you cannot figure out how to generate the vertex buffer object and element buffer object, the code for SGCLPStarDisplay::initialise is here.

void SGCLPStarDisplay::initialise(){ SGLArray<float> vt(2 * (1 + 2 * vertexCount)); vt.at(0) = 0.0f; vt.at(1) = 0.0f; float outerRadius = 0.9f; float innerRadius = outerRadius * SGLFloatMath::sine(0.1f * SGLFloatConstants::pi()) / SGLFloatMath::sine(0.7f * SGLFloatConstants::pi()); for(int i=0; i<vertexCount; i++){ float angle = -0.5f * SGLFloatConstants::pi() + 2.0f * SGLFloatConstants::pi() /static_cast<float>(vertexCount) * (static_cast<float>(i) + 0.5f); vt.at(2 + 2 * i) = innerRadius * SGLFloatMath::cosine(angle); vt.at(3 + 2 * i) = innerRadius * SGLFloatMath::sine(angle); } for(int i=0; i<vertexCount; i++){ float angle = -0.5f * SGLFloatConstants::pi() + 2.0f * SGLFloatConstants::pi() /static_cast<float>(vertexCount) * static_cast<float>(i); vt.at(2 + 2 * vertexCount + 2 * i) = outerRadius * SGLFloatMath::cosine(angle); vt.at(3 + 2 * vertexCount + 2 * i) = outerRadius * SGLFloatMath::sine(angle); } vbo = new SGRVertexBufferObject(this, 4 * 2 * (1 + 2 * vertexCount)); (*renderingProgramme()).updateDataBuffer(vbo, 0, 4 * 2 * (1 + 2 * vertexCount), vt.pointerToData(0)); SGLArray<int> et(3 * 2 * vertexCount); for(int i=0; i<vertexCount; i++){ et.at(3 * i) = 0; et.at(3 * i + 1) = i + 1; et.at(3 * i + 2) = i + 2; } et.at(3 * vertexCount - 1) = 1; for(int i=0; i<vertexCount; i++){ et.at(3 * vertexCount + 3 * i) = i + 1; et.at(3 * vertexCount + 3 * i + 1) = i + 2; et.at(3 * vertexCount + 3 * i + 2) = vertexCount + i + 2; } et.at(6 * vertexCount - 2) = 1; et.at(6 * vertexCount - 1) = vertexCount + 1; ebo = new SGRElementBufferObject(this, 4 * 3 * 2 * vertexCount); (*renderingProgramme()).updateDataBuffer(ebo, 0, 4 * 3 * 2 * vertexCount, et.pointerToData(0)); SGLArray<float> ut(foregroundColour.getRedAsFloat(), foregroundColour.getGreenAsFloat(), foregroundColour.getBlueAsFloat(), foregroundColour.getTransparencyAsFloat()); (*renderingProgramme()).updateShaderUniforms(1, 0, 16, ut.pointerToData(0)); }

When we were writing SGCLPPolygonDisplay, we focused on trigulations. Now we will focus on the actual implementation.

First note that instead of using ‹cmath› to get sine and cosine and ‹numbers› to get the value of pi, we used SGLFloatMath and SGLFloatConstants. These are SGEXTN wrappers for the same Standard Template Library functions. Using these means that you do not need to include ‹cmath› and ‹numbers› to use their functionality, allowing much faster clang-tidy passes.

Apart from SGLFloatConstants and SGLFloatMath, there is also SGLFloatLimits, SGLIntMath, SGLIntLimits, SGLLongLongMath, and SGLLongLongLimits. These also wrap ‹cmath›, ‹numbers›, and ‹numeric_limits›, speeding up clang-tidy checks.

Once you have done testing and debugging, you can run a clang-tidy check and commit to GitHub.

See here for the next part of the tutorial.

©2025 05524F.sg (Singapore)

contact 05524F / report a bug / make a suggestion

about 05524F SINGAPORE values

list of 05524F projects