-
Notifications
You must be signed in to change notification settings - Fork 50
demo
###A CLOSER LOOK AT THE DEMO
This is the last stop before entering the software pipeline. I will briefly analyse a demonstration programme, through which I am sure that you will understand the APIs easily and quickly.
The ‘earth’ demo is called ‘test’ in the VS solution. 70% of the code interacting with the APIs is in the ‘main()’ function, so you can start from there. The following sequence tables summaries the main steps about how the demo calls the APIs.
(The code snippet in the table below is simplified. For a complete version, you can open the source code.)
/*
Create and initialize the DirectDraw based blitter, and use it to initialize the core
module. The core module only needs 3 things to start working, they are:
1. The handle of the window where your scene will be drawn.
2. The width and height of the area on the window will be drawn.
3. The blitter the core module will use to transfer the content in frame buffer
onto screen.
*/
PuresoftRenderer* ddrawRender = new PuresoftDDrawRenderer;
try
{
ddrawRender->startup((uintptr_t)hWnd, W, H);
}
catch(...)
{
MessageBoxW(hWnd, L"Failed to initialize DDraw device…", L"…", MB_OK);
ddrawRender = NULL;
}
PuresoftPipeline pipeline((uintptr_t)hWnd, W, H, ddrawRender);
/*
Prepare the scene, including loading meshes, textures, and creating processor programme
instances. For this step, the real code is wrapped in the class SceneObject, and its derives.
We will show them in the next table.
*/
SceneObject root(pipeline, NULL);
Earth earth(pipeline, &root);
Cloud cloud(pipeline, &root);
Moon moon(pipeline, &root);
Skybox skybox(pipeline, &root);
/*
Preparation for drawing shadow map include:
Creating view and projection matrices for the light source’s viewpoint.
Creating a texture as the shadow map.
Creating dedicated processors for shadow map drawing.
(Please ignore the mcemaths_xxx functions for now as they are not important at this moment)
*/
mat4 light1View, light1Proj, light1pv, light1pvb;
mcemaths_make_proj_perspective(light1Proj, 0.1f, 10.0f, (float)SHDW_W / SHDW_H, 2*PI*(30.0f/360.0f));
mcemaths_make_view_traditional(light1View, lightPos, vec4(), vec4(0, 1.0f, 0, 0));
mcemaths_transform_m4m4(light1pv, light1Proj, light1View);
mcemaths_transform_m4m4(light1pvb, bias, light1pv);
PURESOFTIMGBUFF32 shadowBuffer;
shadowBuffer.width = SHDW_W;
shadowBuffer.height = SHDW_H;
shadowBuffer.elemLen = 4; // 1 float
shadowBuffer.scanline = SHDW_W * 4;
shadowBuffer.pixels = NULL;
int texShadow = pipeline.createTexture(&shadowBuffer);
SceneObject::m_defaultShadowProgramme = pipeline.createProgramme(
pipeline.addProcessor(new VertexProcesserDEF05),
pipeline.addProcessor(new InterpolationProcessorDEF05),
pipeline.addProcessor(new FragmentProcessorDEF05));
/*
The rendering loop begins here.
Firstly, let the scene objects calculate their model space to world space transform
matrices.
*/
while (true)
{
// update objects' positions
root.update((float)highTimer.span() / 1000.0f, rootTransform);
/*
Secondly, draw shadow map.
Apply view and projection matrices representing the light source’s viewpoint, and
then issue draw-call.
*/
// create shadow map
pipeline.setUniform(0, light1Proj, sizeof(light1Proj.elem));
pipeline.setUniform(1, light1View, sizeof(light1View.elem));
pipeline.setUniform(3, light1pv, sizeof(light1pv.elem));
pipeline.setDepth(texShadow);
pipeline.clearDepth();
pipeline.setViewport(SHDW_W, SHDW_H);
SceneObject::m_useShadowProgramme = true;
earth.draw(pipeline);
cloud.draw(pipeline);
moon.draw(pipeline);
/*
Thirdly, draw real scene.
Apply view and projection matrices representing the observer’s viewpoint, and then
issue the second draw-call.
There is one more important step here. Do you see the last statement in the rendering
loop? It calls the swapBuffers() function to show the scene content created by the above
steps onto screen. This function swaps the front and back buffers, wait for the blitter
to finish the previous blitting and give it the front buffer for the next blitting.
While the new blitting starts off, the function returns immediately so that the next scene
drawing can run simultaneously.
*/
// draw scene
pipeline.setUniform(0, proj, sizeof(proj.elem));
pipeline.setUniform(1, view, sizeof(view.elem));
pipeline.setUniform(3, proj_view, sizeof(proj_view.elem));
pipeline.setDepth();
pipeline.clearDepth();
pipeline.setViewport(W, H);
SceneObject::m_useShadowProgramme = false;
SceneObject::m_shadowMaps[0] = texShadow;
mcemaths_mat4cpy(SceneObject::m_shadowPVs[0], light1pvb);
skybox.draw(pipeline);
earth.draw(pipeline);
cloud.draw(pipeline);
moon.draw(pipeline);
pipeline.swapBuffers();
}
One last thing we have not mentioned yet is the processor programme (similar to shaders in OpenGL). There are 3 types of them, and they are listed below.
Processor programme | Input | Output | Purpose |
---|---|---|---|
Vertex Processor | VBOs | Vertex in clip space | Similar to GPU’s vertex shader |
Vertex attributes | |||
Interpolation Processor | Vertex in clip space | Interpolated depth and vertex attributes | Complete interpolation by applying interpolation factors to vertex attributes |
Vertex attributes | |||
Interpolation factors | |||
Fragment Processor | Interpolated vertex attributes | Fragment colour (or other user-defined output) | Similar to GPU’s fragment shader |
More details about how to write Puresoft3D processor programme can be found in API readme document.