3.1.0 release.

This commit is contained in:
harfang3dadmin 2021-12-15 20:23:12 +01:00
parent eeff062611
commit ecd4dad0d6
194 changed files with 9517 additions and 10695 deletions

View File

@ -293,7 +293,7 @@ if(HG_BINDING_DEFINES_LIST)
set(HG_BINDING_DEFINES "--defines" ${HG_BINDING_DEFINES_LIST})
endif()
if( HG_BUILD_CPP_SDK OR HG_BUILD_ASSIMP_CONVERTER OR HG_BUILD_FBX_CONVERTER OR HG_BUILD_GLTF_EXPORTER OR HG_BUILD_GLTF_IMPORTER OR HG_BUILD_ASSETC )
if(HG_BUILD_HG_LUA OR HG_BUILD_CPP_SDK OR HG_BUILD_ASSIMP_CONVERTER OR HG_BUILD_FBX_CONVERTER OR HG_BUILD_GLTF_EXPORTER OR HG_BUILD_GLTF_IMPORTER OR HG_BUILD_ASSETC)
add_subdirectory(extern)
add_subdirectory(binding)
endif()

View File

@ -1114,11 +1114,10 @@ Article 8 - COMMERCIAL USE of the SOFTWARE
USERS who wish to use the SOFTWARE for COMMERCIAL PURPOSES should, prior to
placing a FINAL PRODUCT on the market, complete a COMMERCIALISATION DECLARATION
for NWNC, which can be accessed at the following address:
www.harfang3d.com/declaration.
for NWNC by sending an email to contact@harfang3d.com.
Companies must pay the appropriate rates for the COMMERCIALISATION DECLARATION,
which can be viewed at the following address: www.harfang3d.com/declaration.
which can be consulted by sending an email to contact@harfang3d.com.
The USER will be charged for any COMMERCIAL USE of the SOFTWARE in compliance
with NWNCs rates which entered into force on the same day as the
@ -1139,8 +1138,8 @@ FINAL PRODUCT lawfully with regard to NWNC.
The USER may affix a certification number to the FINAL PRODUCT.
The certification number will be freely available to the FINAL USER at the
following address www.harfang3d.com/certificate-check.
The certification number will be freely available to the FINAL USER by sending
an email to contact@harfang3d.com.
The USER consequently agrees to cite the CERTIFICATE OF COMPLIANCE and specify
how the FINAL USER may access it on the FINAL PRODUCT or in the General

View File

@ -977,6 +977,8 @@ def bind_scene(gen):
gen.bind_method(rigid_body, 'SetRestitution', 'void', ['float restitution'])
gen.bind_method(rigid_body, 'GetFriction', 'float', [])
gen.bind_method(rigid_body, 'SetFriction', 'void', ['float friction'])
gen.bind_method(rigid_body, 'GetRollingFriction', 'float', [])
gen.bind_method(rigid_body, 'SetRollingFriction', 'void', ['float rolling_friction'])
gen.end_class(rigid_body)
@ -990,6 +992,8 @@ def bind_scene(gen):
gen.bind_method(collision, 'GetType', 'hg::CollisionType', [])
gen.bind_method(collision, 'SetType', 'void', ['hg::CollisionType type'])
gen.bind_method(collision, 'GetLocalTransform', 'hg::Mat4', [])
gen.bind_method(collision, 'SetLocalTransform', 'void', ['hg::Mat4 m'])
gen.bind_method(collision, 'GetMass', 'float', [])
gen.bind_method(collision, 'SetMass', 'void', ['float mass'])
gen.bind_method(collision, 'GetRadius', 'float', [])
@ -1307,8 +1311,8 @@ def bind_scene(gen):
protos = [('hg::Node', ['hg::Scene &scene', 'const hg::Mat4 &mtx', 'const hg::ModelRef &model', 'const std::vector<hg::Material> &materials'], [])]
gen.bind_function_overloads('hg::CreateObject', expand_std_vector_proto(gen, protos))
gen.bind_function('hg::CreateInstanceFromFile', 'hg::Node', ['hg::Scene &scene', 'const hg::Mat4 &mtx', 'const std::string &name', 'hg::PipelineResources &resources', 'const hg::PipelineInfo &pipeline', '?uint32_t flags'], {'constants_group': {'flags': 'LoadSaveSceneFlags'}})
gen.bind_function('hg::CreateInstanceFromAssets', 'hg::Node', ['hg::Scene &scene', 'const hg::Mat4 &mtx', 'const std::string &name', 'hg::PipelineResources &resources', 'const hg::PipelineInfo &pipeline', '?uint32_t flags'], {'constants_group': {'flags': 'LoadSaveSceneFlags'}})
gen.bind_function('hg::CreateInstanceFromFile', 'hg::Node', ['hg::Scene &scene', 'const hg::Mat4 &mtx', 'const std::string &name', 'hg::PipelineResources &resources', 'const hg::PipelineInfo &pipeline', 'bool &success', '?uint32_t flags'], {'constants_group': {'flags': 'LoadSaveSceneFlags'}, 'arg_out': ['success']})
gen.bind_function('hg::CreateInstanceFromAssets', 'hg::Node', ['hg::Scene &scene', 'const hg::Mat4 &mtx', 'const std::string &name', 'hg::PipelineResources &resources', 'const hg::PipelineInfo &pipeline', 'bool &success', '?uint32_t flags'], {'constants_group': {'flags': 'LoadSaveSceneFlags'}, 'arg_out': ['success']})
gen.bind_function('hg::CreateScript', 'hg::Node', ['hg::Scene &scene', '?const std::string &path'])
@ -1497,6 +1501,7 @@ static std::vector<hg::ForwardPipelineLight> _GetSceneForwardPipelineLights(cons
gen.bind_function('hg::CreateForwardPipelineAAAFromFile', 'hg::ForwardPipelineAAA', ['const char *path', 'const hg::ForwardPipelineAAAConfig &config', '?bgfx::BackbufferRatio::Enum ssgi_ratio', '?bgfx::BackbufferRatio::Enum ssr_ratio'])
gen.bind_function('hg::CreateForwardPipelineAAAFromAssets', 'hg::ForwardPipelineAAA', ['const char *path', 'const hg::ForwardPipelineAAAConfig &config', '?bgfx::BackbufferRatio::Enum ssgi_ratio', '?bgfx::BackbufferRatio::Enum ssr_ratio'])
gen.bind_function('hg::DestroyForwardPipelineAAA', 'void', ['hg::ForwardPipelineAAA &pipeline'])
gen.bind_function('hg::IsValid', 'bool', ['const hg::ForwardPipelineAAA &pipeline'])
gen.bind_function('hg::UpdateForwardPipelineAAA', 'void', ['hg::ForwardPipeline &pipeline', 'const hg::Rect<int> &rect', 'const hg::Mat4 &view', 'const hg::Mat44 &proj',
'const hg::Mat4 &prv_view', 'const hg::Mat44 &prv_proj', 'const hg::tVec2<float> &jitter', 'bgfx::BackbufferRatio::Enum ssgi_ratio', 'bgfx::BackbufferRatio::Enum ssr_ratio', 'float temporal_aa_weight', 'float motion_blur_strength',
@ -1544,7 +1549,7 @@ def bind_bullet3_physics(gen):
# gen.bind_method(newton, 'CollectCollisionEvents', 'void', ['const hg::Scene &scene', 'hg::NodeNodeContacts &node_node_contacts'])
gen.bind_method(bullet, 'SyncKinematicBodiesFromScene', 'void', ['const hg::Scene &scene'])
gen.bind_method(bullet, 'SyncBodiesFromScene', 'void', ['const hg::Scene &scene'])
gen.bind_method(bullet, 'GarbageCollect', 'size_t', ['const hg::Scene &scene'])
gen.bind_method(bullet, 'GarbageCollectResources', 'size_t', [])
@ -1555,6 +1560,11 @@ def bind_bullet3_physics(gen):
#
gen.bind_method(bullet, 'NodeWake', 'void', ['const hg::Node &node'])
gen.bind_method(bullet, 'NodeSetDeactivation', 'void', ['const hg::Node &node', 'bool enable'])
gen.bind_method(bullet, 'NodeGetDeactivation', 'bool', ['const hg::Node &node'])
gen.bind_method(bullet, 'NodeResetWorld', 'void', ['const hg::Node &node', 'const hg::Mat4 &world'])
gen.bind_method(bullet, 'NodeAddForce', 'void', ['const hg::Node &node', 'const hg::Vec3 &F', '?const hg::Vec3 &world_pos'])
gen.bind_method(bullet, 'NodeAddImpulse', 'void', ['const hg::Node &node', 'const hg::Vec3 &dt_velocity', '?const hg::Vec3 &world_pos'])
gen.bind_method(bullet, 'NodeGetPointVelocity', 'hg::Vec3', ['const hg::Node &node', 'const hg::Vec3 &world_pos'])
@ -1564,6 +1574,11 @@ def bind_bullet3_physics(gen):
gen.bind_method(bullet, 'NodeGetAngularVelocity', 'hg::Vec3', ['const hg::Node &node'])
gen.bind_method(bullet, 'NodeSetAngularVelocity', 'void', ['const hg::Node &node', 'const hg::Vec3 &W'])
gen.bind_method(bullet, 'NodeGetLinearLockAxes', 'void', ['const hg::Node &node', 'bool &X', 'bool &Y', 'bool &Z'], {'arg_out': ['X', 'Y', 'Z']})
gen.bind_method(bullet, 'NodeSetLinearLockAxes', 'void', ['const hg::Node &node', 'bool X', 'bool Y', 'bool Z'])
gen.bind_method(bullet, 'NodeGetAngularLockAxes', 'void', ['const hg::Node &node', 'bool &X', 'bool &Y', 'bool &Z'], {'arg_out': ['X', 'Y', 'Z']})
gen.bind_method(bullet, 'NodeSetAngularLockAxes', 'void', ['const hg::Node &node', 'bool X', 'bool Y', 'bool Z'])
#
node_contacts = gen.begin_class('hg::NodeContacts')
gen.end_class(node_contacts)
@ -1594,6 +1609,7 @@ static std::vector<hg::Contact> __GetNodeContacts(const hg::NodeContacts &ctcs,
#
gen.bind_method(bullet, 'RaycastFirstHit', 'hg::RaycastOut', ['const hg::Scene &scene', 'const hg::Vec3 &p0', 'const hg::Vec3 &p1'])
gen.bind_method(bullet, 'RaycastAllHits', 'std::vector<hg::RaycastOut>', ['const hg::Scene &scene', 'const hg::Vec3 &p0', 'const hg::Vec3 &p1'])
#
gen.bind_method(bullet, 'RenderCollision', 'void', ['bgfx::ViewId view_id', 'const bgfx::VertexLayout &vtx_layout', 'bgfx::ProgramHandle prg', 'hg::RenderState render_state', 'uint32_t depth'])
@ -2114,6 +2130,8 @@ static void _SetViewTransform(bgfx::ViewId view_id, const hg::Mat4 &view, const
('TF_SamplerMinAnisotropic', 'BGFX_SAMPLER_MIN_ANISOTROPIC'),
('TF_SamplerMagPoint', 'BGFX_SAMPLER_MAG_POINT'),
('TF_SamplerMagAnisotropic', 'BGFX_SAMPLER_MAG_ANISOTROPIC'),
('TF_BlitDestination', 'BGFX_TEXTURE_BLIT_DST'),
('TF_ReadBack', 'BGFX_TEXTURE_READ_BACK'),
], 'TextureFlags')
gen.bind_function('hg::LoadTextureFlagsFromFile', 'uint64_t', ['const std::string &path'], {'rval_constants_group': 'TextureFlags'})
@ -2394,16 +2412,27 @@ static bgfx::TextureInfo _PipelineResources_GetTextureInfo(hg::PipelineResources
gen.bind_function('hg::CreateMissingMaterialProgramValuesFromAssets', 'void', ['hg::Material &mat', 'const hg::PipelineResources &resources'])
#
pipeline_frame_buffer = gen.begin_class('hg::PipelineFrameBuffer')
gen.bind_members(pipeline_frame_buffer, ['bgfx::FrameBufferHandle handle', 'hg::TextureRef color', 'hg::TextureRef depth'])
gen.end_class(pipeline_frame_buffer)
frame_buffer = gen.begin_class('hg::FrameBuffer')
gen.bind_member(frame_buffer, 'bgfx::FrameBufferHandle handle')
gen.end_class(frame_buffer)
gen.bind_function_overloads('hg::CreateFrameBuffer', [
('hg::PipelineFrameBuffer', ['bgfx::TextureFormat::Enum color_format', 'bgfx::TextureFormat::Enum depth_format', 'int aa', 'hg::PipelineResources &res', 'const char *name'], []),
('hg::PipelineFrameBuffer', ['int width', 'int height', 'bgfx::TextureFormat::Enum color_format', 'bgfx::TextureFormat::Enum depth_format', 'int aa', 'hg::PipelineResources &res', 'const char *name'], [])
('hg::FrameBuffer', ['const hg::Texture &color', 'const hg::Texture &depth', 'const char *name'], []),
('hg::FrameBuffer', ['bgfx::TextureFormat::Enum color_format', 'bgfx::TextureFormat::Enum depth_format', 'int aa', 'const char *name'], []),
('hg::FrameBuffer', ['int width', 'int height', 'bgfx::TextureFormat::Enum color_format', 'bgfx::TextureFormat::Enum depth_format', 'int aa', 'const char *name'], [])
])
gen.bind_function('hg::DestroyFrameBuffer', 'void', ['hg::PipelineResources &res', 'hg::PipelineFrameBuffer &frameBuffer'])
gen.bind_function('hg::GetColorTexture', 'hg::Texture', ['hg::FrameBuffer &frameBuffer'])
gen.bind_function('hg::GetDepthTexture', 'hg::Texture', ['hg::FrameBuffer &frameBuffer'])
gen.insert_binding_code('''
static void _FrameBuffer_GetTextures(hg::FrameBuffer &framebuffer, hg::Texture &color, hg::Texture &depth) {
color = hg::GetColorTexture(framebuffer);
depth = hg::GetDepthTexture(framebuffer);
}
''')
gen.bind_function('GetTextures', 'void', ['hg::FrameBuffer &framebuffer', 'hg::Texture &color', 'hg::Texture &depth'], {'route': route_lambda('_FrameBuffer_GetTextures'), 'arg_out': ['color', 'depth']})
gen.bind_function('hg::DestroyFrameBuffer', 'void', ['hg::FrameBuffer &frameBuffer'])
#
vertices = gen.begin_class('hg::Vertices')
@ -2786,6 +2815,11 @@ def bind_color(gen):
gen.bind_function('hg::ColorI', 'hg::Color', ['int r', 'int g', 'int b', '?int a'])
gen.bind_function('hg::ToHLS', 'hg::Color', ['const hg::Color &color'])
gen.bind_function('hg::FromHLS', 'hg::Color', ['const hg::Color &color'])
gen.bind_function('hg::SetSaturation', 'hg::Color', ['const hg::Color &color', 'float saturation'])
bind_std_vector(gen, color)

View File

@ -1,33 +1,38 @@
# Generates the Harfang API XML description used to generate the documentation.
add_custom_command(
OUTPUT
${CMAKE_CURRENT_BINARY_DIR}/harfang/api.xml
COMMAND
${Python3_EXECUTABLE} bind.py ${CMAKE_CURRENT_SOURCE_DIR}/../binding/bind_harfang.py --xml --out ${CMAKE_CURRENT_BINARY_DIR}/harfang ${HG_BINDING_DEFINES}
MAIN_DEPENDENCY
${CMAKE_SOURCE_DIR}/binding/bind_harfang.py
WORKING_DIRECTORY
${HG_FABGEN_PATH}
COMMENT
"Generating Harfang API description file")
# online docs
add_custom_target(online_docs ALL
${Python3_EXECUTABLE} doc_to_html.py --project_name Harfang --doc_path doc --api_path ${CMAKE_CURRENT_BINARY_DIR}/harfang/api.xml --out_path ${CMAKE_INSTALL_PREFIX}/online_docs --version ${HG_VERSION} --online
WORKING_DIRECTORY
${CMAKE_CURRENT_SOURCE_DIR}
DEPENDS
${CMAKE_CURRENT_BINARY_DIR}/harfang/api.xml)
install(DIRECTORY img DESTINATION online_docs COMPONENT online_docs)
set_target_properties(online_docs PROPERTIES FOLDER "harfang/doc")
add_custom_command(
OUTPUT
${CMAKE_CURRENT_BINARY_DIR}/harfang/api.xml
COMMAND
${Python3_EXECUTABLE} bind.py ${CMAKE_SOURCE_DIR}/binding/bind_harfang.py --xml --out ${CMAKE_CURRENT_BINARY_DIR}/harfang ${HG_BINDING_DEFINES}
MAIN_DEPENDENCY
${CMAKE_SOURCE_DIR}/binding/bind_harfang.py
WORKING_DIRECTORY
${HG_FABGEN_PATH}
COMMENT
"Generating Harfang API description file")
add_custom_target(gen_api_xml ALL DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/harfang/api.xml)
# add_custom_command(
# OUTPUT
# ${CMAKE_CURRENT_BINARY_DIR}/harfang/api.xml
# COMMAND
# ${Python3_EXECUTABLE} bind.py ${CMAKE_CURRENT_SOURCE_DIR}/../binding/bind_harfang.py --xml --out ${CMAKE_CURRENT_BINARY_DIR}/harfang ${HG_BINDING_DEFINES}
# MAIN_DEPENDENCY
# ${CMAKE_SOURCE_DIR}/binding/bind_harfang.py
# WORKING_DIRECTORY
# ${HG_FABGEN_PATH}
# COMMENT
# "Generating Harfang API description file")
# offline docs
configure_file(doc/index.html.in ${CMAKE_INSTALL_PREFIX}/offline_docs/index.html @ONLY IMMEDIATE)
add_custom_target(offline_docs ALL
${Python3_EXECUTABLE} doc_to_html.py --project_name Harfang --doc_path doc --api_path ${CMAKE_CURRENT_BINARY_DIR}/harfang/api.xml --out_path ${CMAKE_INSTALL_PREFIX}/offline_docs --version ${HG_VERSION}
WORKING_DIRECTORY
${CMAKE_CURRENT_SOURCE_DIR}
DEPENDS
${CMAKE_CURRENT_BINARY_DIR}/harfang/api.xml)
install(DIRECTORY img DESTINATION offline_docs/content COMPONENT offline_docs)
set_target_properties(offline_docs PROPERTIES FOLDER "harfang/doc")
#configure_file(doc/index.html.in ${CMAKE_INSTALL_PREFIX}/offline_docs/index.html @ONLY IMMEDIATE)
#add_custom_target(offline_docs ALL
# ${Python3_EXECUTABLE} doc_to_html.py --project_name Harfang --doc_path doc --api_path ${CMAKE_CURRENT_BINARY_DIR}/harfang/api.xml --out_path ${CMAKE_INSTALL_PREFIX}/offline_docs --version ${HG_VERSION}
# WORKING_DIRECTORY
# ${CMAKE_CURRENT_SOURCE_DIR}
# DEPENDS
# ${CMAKE_CURRENT_BINARY_DIR}/harfang/api.xml)
#install(DIRECTORY img DESTINATION offline_docs/content COMPONENT offline_docs)
#set_target_properties(offline_docs PROPERTIES FOLDER "harfang/doc")

1
doc/doc/FromHLS.md Normal file
View File

@ -0,0 +1 @@
Convert input hue/luminance/saturation color to RGBA, alpha channel is left unmodified.

View File

@ -1 +1,3 @@
Return the total elapsed time since the object creation or the last call to [ResetClock].
Return the current clock since the last call to [TickClock] or [ResetClock].
See [time_to_sec_f] to convert the returned time to second.

View File

@ -0,0 +1 @@
Retrieves color texture attachment.

View File

@ -0,0 +1 @@
Retrieves depth texture attachment.

1
doc/doc/GetTextures.md Normal file
View File

@ -0,0 +1 @@
Returns color and depth texture attachments.

View File

@ -1 +1,5 @@
Checkbox widget returning the check state.
Display a checkbox widget. Returns an interaction flag (user interacted with the widget) and the current widget state (checked or not after user interaction).
```python
was_clicked, my_value = gs.ImGuiCheckBox('My value', my_value)
```

3
doc/doc/SetSaturation.md Normal file
View File

@ -0,0 +1,3 @@
Return a copy of the input RGBA color with its saturation set to the specified value, alpha channel is left unmodified.
See [ToHLS] and [FromHLS].

View File

@ -1,3 +1,3 @@
Record the elapsed time since the last call to this function.
Advance the engine clock and return the elapsed time since the last call to this function. See [GetClock] to retrieve the current clock.
See [GetClockDt].

1
doc/doc/ToHLS.md Normal file
View File

@ -0,0 +1 @@
Convert input RGBA color to hue/luminance/saturation, alpha channel is left unmodified.

View File

@ -1,3 +0,0 @@
.title Function/member index
%AllFunctionIndex%

View File

@ -1,76 +0,0 @@
.title An application using the render system
This page describes a complete Harfang application in Python displaying a triangle using the [RenderSystem].
.img("man.AnApplicationUsingTheRenderSystem.png")
The complete source for this application can be found in the [man.Tutorials].
## Program overview
To display a triangle using the render system we will need to:
1. Create the renderer and a render system wrapping it,
* Display the triangle in a loop until the end of execution condition is met.
Most steps of this program are explained in details in the [man.AnApplicationUsingTheRenderer] page.
## Creating the render system
This application uses [Renderer] and wraps it with [RenderSystem].
```python
# create the renderer
renderer = hg.CreateRenderer()
renderer.Open()
# open a new window
win = hg.NewWindow(480, 240)
# create a new output surface for the newly opened window
surface = renderer.NewOutputSurface(win)
renderer.SetOutputSurface(surface)
# initialize the render system, which is used to draw through the renderer
render_system = hg.RenderSystem()
render_system.Initialize(renderer)
```
The render system is ready to work.
## The application render loop
### A word on vertex transformation
Since we will be displaying the triangle using the render system we have less control over the shader that is going to be used. The render system core resources include shader to render all the common combination of vertex attributes.
However, unlike the the shader we used in the equivalent renderer program, _all render system shaders make use of the renderer ModelViewProjection matrix_. So we first need to initialize it.
For the purpose of this program a simple 2D projection system will do. The following call will set a projection matrix that maps vertex coordinate to pixels with (0;0) in the lower-left corner of the viewport with +X going right and +Y going up.
```python
renderer.Set2DMatrices()
```
### Drawing the triangle
The application loops until the default renderer window is closed and starts by clearing the render target to a solid green color.
```python
while hg.IsWindowOpen(win):
renderer.Clear(hg.Color.Green)
```
Next, we tell the render system to draw the triangle using the helper function it provides for this task.
```python
vertices = [hg.Vector3(0, 0, 0), hg.Vector3(0, 240, 0), hg.Vector3(480, 240, 0)]
render_system.DrawTriangleAuto(1, vertices, color)
```
Finally, the loop ends by showing the draw result and updating the renderer output window.
```python
hg.Frame()
hg.UpdateWindow(win)
```

View File

@ -1,159 +0,0 @@
.title An application using the renderer
This page describes a complete Harfang application in Python displaying a triangle using the [Renderer].
The complete source for this application can be found in the [man.Tutorials].
## Program overview
To display a triangle using the renderer we will need to:
1. Create the renderer,
* Create a window and ,
* Describe the geometry we intend to draw,
* Provide the geometry to the renderer along with a shader to draw it.
* Display the triangle in a loop until the end of execution condition is met.
## Creating the renderer
We first need to create an object of [Renderer] type. By default this application uses the OpenGL implementation of the renderer interface, but any other available implementation can be used in its place.
```python
renderer = hg.CreateRenderer()
renderer.Open()
```
The [Renderer] object is first created then its [Renderer_Open] member function is called. At this point no window is created.
## Creating the window
We create a new [Window] using the [NewWindow] function.
```python
win = hg.NewWindow(640, 480)
```
We create a [Surface] for the newly created window and set it as the [Renderer] new output surface.
```python
surface = renderer.NewOutputSurface(win)
renderer.SetOutputSurface(surface)
```
## Describing the geometry to draw
The [Renderer] API works at the lowest level of abstraction and uses [GpuBuffer] and [VertexLayout] together with a [Shader] to build and draw primitives.
### Index buffer
A triangle is build from 3 vertices which are connected in sequential order (vertex 0 to vertex 1 to vertex 2). So we need a vertex buffer of 3 vertices and an index buffer of 3 indexes containing the following values: 0, 1 and 2.
The index values need to be packed into a memory buffer before they can be send to the gpu. The [BinaryBlob] class can be used to this effect.
```python
data = gs.BinaryData()
data.WriteUInt16s([0, 1, 2]) # we use 16 bit packing of the index values by writing shorts
```
The index buffer is then very easily constructed from the binary blob.
```python
idx = renderer.NewBuffer()
renderer.CreateBuffer(idx, data, hg.GpuBufferIndex)
```
### Vertex buffer
A vertex can be made of any number of attributes (position, color, UV, etc...) which are then fed into the shader used to draw the primitives. To specify the layout of a vertex buffer we use the [VertexLayout] class.
The triangle we will display is the simplest one possible, displaying a single color provided as a shader parameter, so its vertices only need a position attribute. The position of each vertex will be stored using 3 float values.
```python
vtx_layout = hg.VertexLayout()
vtx_layout.AddAttribute(hg.VertexPosition, 3, hg.VertexFloat)
```
We then prepare the vertex buffer content using another binary blob.
```python
data = hg.BinaryData()
data.WriteFloats([-0.5, -0.5, 0.5, -0.5, 0.5, 0.5, 0.5, 0.5, 0.5])
```
We can now create the vertex buffer.
```python
vtx = renderer.NewBuffer()
renderer.CreateBuffer(vtx, data, hg.GpuBufferVertex)
```
The buffers are complete and ready to render.
## Create a shader to render the geometry
The shader we use to display the triangle takes the vertex position as it is and output the same color for each pixel. The output color is an input parameter named `u_color` which we will programmatically change.
```glsl
in { vec4 u_color; }
variant {
vertex {
out { vec4 v_color; }
source %{
v_color = u_color;
%out.position% = vec4(vPosition, 1.0);
%}
}
pixel {
in { vec4 v_color; }
source %{
%out.color% = v_color;
%}
}
}
```
For more information on the shader structure, refer to the [man.Shader] page.
To load the shader from a file we first mount a file driver (cf. [man.Assets]).
```python
hg.MountFileDriver(hg.StdFileDriver())
shader_path = os.path.join(os.getcwd(), "../_data/shader_2d_color.isl")
shader = renderer.LoadShader(shader_path)
```
**Note:** A default value for `u_color` can be specified in the shader declaration so that we do not have to set it programmatically.
## The application render loop
Everything is now ready so we enter the main application loop in which we render the triangle. The application loops until the default renderer window is closed and starts by clearing the render target to a solid red color.
```python
while hg.IsWindowOpen(win):
renderer.Clear(hg.Color.Red)
```
Next, the shader and its `u_color` input value are set and the index/vertex buffers are drawn to the render target.
```python
renderer.SetShader(shader)
renderer.SetShaderFloat4("u_color", 0, 1, 0, 1)
hg.DrawBuffers(renderer, 3, idx, vtx, vtx_layout)
```
**Note:** The [DrawBuffers] call specifies the drawing of 3 indexes and uses the default value for the index type and primitive type. Those are 16 bit indexes and triangle primitives.
Finally, the loop ends by commiting the draw call, showing the draw result and updating the renderer output window.
```python
renderer.DrawFrame()
renderer.ShowFrame()
hg.UpdateWindow(win)
hg.EndFrame()
```

View File

@ -1 +0,0 @@
.title Architecture

View File

@ -1,5 +0,0 @@
.title Overview
Assemble is a scene editor for the Harfang library written in C++ using the DearImGui library.
It can be used to prepare assets for your Harfang programs or as a stand-alone content creation tool with publishing capabilities.

View File

@ -1,14 +1,14 @@
.title Resources & Assets
By convention, we call production files: **resources** (eg. *the project resources*).
By convention, production files are called: **resources** (eg. *the project resources*).
Files issued from the compilation of production files for a specific target are called: **assets** (eg. *the project assets for iOS*).
Files issued from the compilation of production files for a specific target are called: **assets** (eg. *the project assets for Windows PC*).
[TOC]
## Resource Formats
During development resources are stored in *production formats*, these formats are meant for efficient editing. Before they can be loaded at runtime, resources must be compiled into their *runtime formats* as assets which are specific to and optimized for the target platform.
During development resources are stored in *production formats*, these formats are meant for efficient editing. Before they can be loaded at runtime, resources must be compiled into their *runtime formats* as assets which are specific to the target platform.
To compile a project resources use:

View File

@ -16,6 +16,20 @@ Harfang 2.0.0 for CPython 3.2+ on windows-x64 (build ba08463ee9e6c0c93960230fb88
See http://harfang3d.com/license for licensing terms
```
### Troubleshooting
> _`pip install` fails with a message saying `harfang is not a supported wheel on this platform`._
>
> Make sure that your pip install is up to date. Outdated pip versions have been known to cause such problems.
> _The dynamic library fails to load when importing the `harfang` module in Python._
>
> Make sure your system has the required runtime dependencies installed. It should have OpenAL and on Windows the Visual C++ 2017 redistributable installed.
> _`ImportError: DLL load failed: %1 is not a valid Win32 application.` error when importing the `harfang` module._
>
> This error usually happens when installing the incorrect version of Harfang for your Python version. For example when installing the 64 bit version of Harfang on a 32 bit install of the Python interpreter.
## First Program
Let's write a simple test program, create a new file named `test.py` and paste the following code into it.

View File

@ -1,3 +0,0 @@
.title API Classes
%ClassIndex%

View File

@ -1,5 +0,0 @@
.title Components
## Node components
[Transform], [Object], [Light], [Camera], [LuaScript], [RigidBody] and [Collision].

View File

@ -1,5 +0,0 @@
.title API Constants
%GlobalConstantsIndex%
%GlobalConstantsDocumentation%

View File

@ -1,3 +0,0 @@
.title Core runtime resources
In order to properly work the Harfang library needs to access a number of core resources.

View File

@ -1,41 +0,0 @@
.title DearImGui
Harfang embeds the [dear imGui](https://github.com/ocornut/imgui) library.
Dear imgui is an immediate GUI library designed to quickly build debugging/profiling user interface.
It is available at all time through the ImGui* function and only requires a [Renderer] instance to work. Only a single instance of the library is available and its output is displayed right before executing a [Renderer_ShowFrame] call.
Accessing ImGui from multiple threads require synchronization using the [ImGuiLock] and [ImGuiUnlock] functions.
### Minimal sample code showing a window
```python
import harfang as hg
hg.LoadPlugins()
renderer = hg.CreateRenderer()
renderer.Open()
win = hg.NewWindow(640, 480)
surface = renderer.NewOutputSurface(win)
renderer.SetOutputSurface(surface)
hg.ImGuiSetOutputSurface(surface)
while True:
hg.ImGuiBegin("window"):
hg.ImGuiEnd()
renderer.Clear(hg.Color.Red)
renderer.ShowFrame()
hg.UpdateWindow(win)
hg.EndFrame()
renderer.DestroyOutputSurface(surface)
hg.DestroyWindow(win)
renderer.Close()
```

View File

@ -1,13 +0,0 @@
.title Debugging
## Debugging general issues
The first thing to check when your program fails is the engine log output. The log output sends all engine debugging messages to the console.
The log system defaults to only displaying warning and error level messages. Enabling debug and standard level messages by calling `hg.SetLogLevel(hg.LogAll)` (see [SetLogLevel]) will simplify identifying why something is going wrong.
Complex error messages might include detailed information on the error. By default, details are filtered out by the system and must be enabled using `hg.SetLogIsDetailed(True)` (see [SetLogIsDetailed]).
## Debugging scene issues
A scene is to complex an object to debug through the log system. The engine debugger includes a scene debugger which is the perfect tool for dwelving into the data structures of a scene. Refer to the [man.EngineDebugger] manual page for how to use it.

View File

@ -1,76 +0,0 @@
.title Drawing graphic primitives
This page describes a complete Harfang application in Python displaying lines, triangles and polygons using low level graphics functionnalities.
.img("man.AnApplicationUsingTheRenderSystem.png")
The complete source for this application can be found in the [man.Tutorials].
## Program overview
To display a triangle using the render system we will need to:
1. Create the renderer and a render system wrapping it,
* Display the triangle in a loop until the end of execution condition is met.
Most steps of this program are explained in details in the [man.AnApplicationUsingTheRenderer] page.
## Creating the render system
This application uses [Renderer] and wraps it with [RenderSystem].
```python
# create the renderer
renderer = hg.CreateRenderer()
renderer.Open()
# open a new window
win = hg.NewWindow(480, 240)
# create a new output surface for the newly opened window
surface = renderer.NewOutputSurface(win)
renderer.SetOutputSurface(surface)
# initialize the render system, which is used to draw through the renderer
render_system = hg.RenderSystem()
render_system.Initialize(renderer)
```
The render system is ready to work.
## The application render loop
### A word on vertex transformation
Since we will be displaying the triangle using the render system we have less control over the shader that is going to be used. The render system core resources include shader to render all the common combination of vertex attributes.
However, unlike the the shader we used in the equivalent renderer program, _all render system shaders make use of the renderer ModelViewProjection matrix_. So we first need to initialize it.
For the purpose of this program a simple 2D projection system will do. The following call will set a projection matrix that maps vertex coordinate to pixels with (0;0) in the lower-left corner of the viewport with +X going right and +Y going up.
```python
renderer.Set2DMatrices()
```
### Drawing the triangle
The application loops until the default renderer window is closed and starts by clearing the render target to a solid green color.
```python
while hg.IsWindowOpen(win):
renderer.Clear(hg.Color.Green)
```
Next, we tell the render system to draw the triangle using the helper function it provides for this task.
```python
vertices = [hg.Vector3(0, 0, 0), hg.Vector3(0, 240, 0), hg.Vector3(480, 240, 0)]
render_system.DrawTriangleAuto(1, vertices, color)
```
Finally, the loop ends by showing the draw result and updating the renderer output window.
```python
hg.Frame()
hg.UpdateWindow(win)
```

View File

@ -1,24 +0,0 @@
.title Engine debugger
Harfang integrates a debugger written in [man.Dearimgui]. The debugger can be used to inspect, debug and profile many systems of the engine at runtime.
Use the [SetEnableDebugger] function to enable and disable the debugger. The debugger interface will overlay itself over your program output before each call to [Renderer_ShowFrame].
## Engine systems
The debugger monitors the following engine systems.
* **Renderer:** Statistics for the current [Renderer].
* **Render system:** Statistics for the current [RenderSystem].
* **Texture cache:** Display the content of the engine texture cache.
* **Geometry cache:** Display the content of the engine geometry cache.
* **Material cache:** Display the content of the engine material cache.
* **Log window:** Display the engine log output.
## Scene debugger
.img("man.scene_debugger.jpg")
The debugger tracks all scene creation and deletion and keeps a list of available scene in the *Scene debugger* menu. You can select a specific scene to monitor or select the *automatic* option from the *Scene debugger* menu to track the last displayed scene.
The scene debugger can display the full scene tree, inspect and modify [Node] and their [man.Component].

View File

@ -1,5 +0,0 @@
.title API Enumerations
%GlobalEnumIndex%
%GlobalEnumDocumentation%

View File

@ -1,7 +0,0 @@
.title Examples
## Note on code examples
Most examples presented in this manual are written in Python.
The API exposed to both languages being identical, adapting the Python examples to Lua usually requires little more than language grammar change.

View File

@ -1,4 +0,0 @@
.title Extending the editor
* [man.ExtendingTheProjectExplorer]
* [man.ExtendingTheScenePlugin]

View File

@ -1,14 +0,0 @@
.title Extending the project explorer
## Writing a project explorer plugin
A scene tool plugin must be declared as a class extending the `plugin.IProjectExplorerPlugin` interface.
```python
class Plugin(IProjectExplorerPlugin):
""" A new project explorer plugin """
```
The following methods must be implemented by the plugin:
* `process_drop_event(dropped_urls, target_url)`: Process a drop event over the project explorer. Return `plugin.InterruptPluginChain` to stop execution at your plugin.

View File

@ -1,24 +0,0 @@
.title Extending the scene plugin
## Writing a scene tool plugin
A scene tool plugin must be declared as a class extending the `plugin.ISceneToolPlugin` interface.
```python
class Plugin(ISceneToolPlugin):
""" New Scene plugin """
```
The following methods must be implemented by the plugin:
* `on_selection_changed(selection)`: Called by the scene plugin whenever the selection is changed. The complete new selection is passed to the plugin.
* `on_node_selection_changed(node_selection)`: Same as above but a list of the scene nodes in the new selection is passed to the plugin.
* `on_frame_complete()`: This function is called when the current frame is complete. The plugin is given a chance to draw additional content at this point.
**Note:** This call is done from the rendering thread. The synchronous renderer object [^1] can be used from this location. The renderer matrix stack is automatically saved and restored around this call.
* `on_mouse_event(event, mouse, dt_frame)`: Called whenever a mouse event happens over the viewport.
[^1]: Available through the `engine.renderer` symbol.
## Mouse events
TODO

View File

@ -1,51 +0,0 @@
.title Feature List
### General
* Cross-platform
* Lightweight code base
* Small memory footprint
### Interoperability
* Command line FBX converter (extensive support including geometry skinning)
* Native support for many image file formats (PSD, JPG, PNG, TGA, ...)
* Native support for many sound file formats (OGG, WAV, AIFF, XM, S3M, ...)
### Framework
* Flexible file system abstraction (local, archive, network components with chaining)
* HID abstraction to access machine devices (DirectInput, XInput, ...)
* Data format abstraction (XML/JSON/Binary back-ends)
* 2D Vector graphics engine based on the Anti Grain Geometry library
### Multi-threading
* Task-based multi-threading
* Asynchronous interfaces to control key API objects from any thread or language
### Audio
* Audio API abstraction layer (OpenAL back-end)
* Any supported audio format can be streamed or loaded as a sound
* 3D audio support
### Rendering
* GPU-accelerated
* Graphic API abstraction layer (OpenGL 3.3/ES 2.0 & DirectX 11 back-ends)
* Shader-based rendering
* Draw TTF text to screen
### Scene
* Complete scene management
* Component/system architecture
* GPU skinning
* Light component with shadow mapping
* Post-processing (motion blur, depth of field, ...)
* Bullet/PhysX 3 physics system
* Recast/Detour navigation system
* Create new component using Lua scripts
* Multiple Lua scripts can run in parallel
* Each scene system executes tasks in parallel using a lock-free stepping algorithm

View File

@ -1,5 +0,0 @@
.title API Functions
%GlobalFunctionIndex%
%GlobalFunctionDocumentation%

View File

@ -1,152 +0,0 @@
.title Generated textured cube
The [Geometry] class contains the functions needed to generate meshes.
## Generated textured cube
To generate a textured cube using [Geometry] API, you need the following functions:
### Vertices
* [Geometry_AllocateVertex] : Set the number of vertices.
* [Geometry_SetVertex] : Set vertex coordinates.
### Polygons
* [Geometry_AllocatePolygon] : Set number of polygons.
* [Geometry_SetPolygon] : Set the number of vertices and the polygon material.
* [Geometry_AllocatePolygonBinding] : Allocate memory to store the geometry polygon binding table.
* [Geometry_SetPolygonBinding] : Set the polygon binding table.
### Normals
* [Geometry_AllocateVertexNormal] : Set the number of normals.
* [Geometry_SetVertexNormal] : Set normal coordinates.
### UVs
* [Geometry_AllocateUVChannels] : Set number of UVs.
* [Geometry_SetUV] : Set UV coordinates.
### Materials
* [Geometry_AllocateMaterialTable] : Set number of materials.
* [Geometry_SetMaterial] : Set material definition file path.
## Code example
### Vertices and polygons
```python
cube = hg.Geometry()
# Create vertex
s = hg.Vector3(1,1,1) # dimensions
cube.AllocateVertex(8)
ube.SetVertex(0, hg.Vector3(-s.x, -s.y, -s.z))
cube.SetVertex(1, hg.Vector3(-s.x, -s.y, s.z))
cube.SetVertex(2, hg.Vector3(-s.x, s.y, -s.z))
cube.SetVertex(3, hg.Vector3(-s.x, s.y, s.z))
cube.SetVertex(4, hg.Vector3(s.x, -s.y, -s.z))
cube.SetVertex(5, hg.Vector3(s.x, -s.y, s.z))
cube.SetVertex(6, hg.Vector3(s.x, s.y, -s.z))
cube.SetVertex(7, hg.Vector3(s.x, s.y, s.z))
# Create polygons
cube.AllocatePolygon(6)
cube.SetPolygon(0, 4, 0)
cube.SetPolygon(1, 4, 1)
cube.SetPolygon(2, 4, 2)
cube.SetPolygon(3, 4, 3)
cube.SetPolygon(4, 4, 4)
cube.SetPolygon(5, 4, 5)
# Polygons bindings
cube.AllocatePolygonBinding()
cube.SetPolygonBinding(0, hg.IntList([0, 2, 6, 4]))
cube.SetPolygonBinding(1, hg.IntList([4, 6, 7, 5]))
cube.SetPolygonBinding(2, hg.IntList([5, 7, 3, 1]))
cube.SetPolygonBinding(3, hg.IntList([1, 3, 2, 0]))
cube.SetPolygonBinding(4, hg.IntList([2, 3, 7, 6]))
cube.SetPolygonBinding(5, hg.IntList([4, 5, 1, 0]))
```
### Normals. Each vertex for each polygon has a normal. So, 6 polygons X 4 vertices = 24 normals
```python
# Normals
cube.AllocateVertexNormal(24)
cube.SetVertexNormal(0, hg.Vector3(0, 0, -1))
cube.SetVertexNormal(1, hg.Vector3(0, 0, -1))
cube.SetVertexNormal(2, hg.Vector3(0, 0, -1))
cube.SetVertexNormal(3, hg.Vector3(0, 0, -1))
cube.SetVertexNormal(4, hg.Vector3(1, 0, 0))
cube.SetVertexNormal(5, hg.Vector3(1, 0, 0))
cube.SetVertexNormal(6, hg.Vector3(1, 0, 0))
cube.SetVertexNormal(7, hg.Vector3(1, 0, 0))
cube.SetVertexNormal(8, hg.Vector3(0, 0, 1))
cube.SetVertexNormal(9, hg.Vector3(0, 0, 1))
cube.SetVertexNormal(10, hg.Vector3(0, 0, 1))
cube.SetVertexNormal(11, hg.Vector3(0, 0, 1))
cube.SetVertexNormal(12, hg.Vector3(-1, 0, 0))
cube.SetVertexNormal(13, hg.Vector3(-1, 0, 0))
cube.SetVertexNormal(14, hg.Vector3(-1, 0, 0))
cube.SetVertexNormal(15, hg.Vector3(-1, 0, 0))
cube.SetVertexNormal(16, hg.Vector3(0, 1, 0))
cube.SetVertexNormal(17, hg.Vector3(0, 1, 0))
cube.SetVertexNormal(18, hg.Vector3(0, 1, 0))
cube.SetVertexNormal(19, hg.Vector3(0, 1, 0))
cube.SetVertexNormal(20, hg.Vector3(0, -1, 0))
cube.SetVertexNormal(21, hg.Vector3(0, -1, 0))
cube.SetVertexNormal(22, hg.Vector3(0, -1, 0))
cube.SetVertexNormal(23, hg.Vector3(0, -1, 0))
```
### UVs and materials
```python
# Create UVs
cube.AllocateUVChannels(1, 24)
cube.SetUV(0, 0, hg.Vector2List([hg.Vector2(0, 0), hg.Vector2(0, 1), hg.Vector2(1, 1), hg.Vector2(1, 0)]))
cube.SetUV(0, 1, hg.Vector2List([hg.Vector2(0, 0), hg.Vector2(0, 1), hg.Vector2(1, 1), hg.Vector2(1, 0)]))
cube.SetUV(0, 2, hg.Vector2List([hg.Vector2(0, 0), hg.Vector2(0, 1), hg.Vector2(1, 1), hg.Vector2(1, 0)]))
cube.SetUV(0, 3, hg.Vector2List([hg.Vector2(0, 0), hg.Vector2(0, 1), hg.Vector2(1, 1), hg.Vector2(1, 0)]))
cube.SetUV(0, 4, hg.Vector2List([hg.Vector2(0, 0), hg.Vector2(0, 1), hg.Vector2(1, 1), hg.Vector2(1, 0)]))
cube.SetUV(0, 5, hg.Vector2List([hg.Vector2(0, 0), hg.Vector2(0, 1), hg.Vector2(1, 1), hg.Vector2(1, 0)]))
# Create materials
cube.AllocateMaterialTable(6)
cube.SetMaterial(0, "assets/materials/face1.mat")
cube.SetMaterial(1, "assets/materials/face2.mat")
cube.SetMaterial(2, "assets/materials/face3.mat")
cube.SetMaterial(3, "assets/materials/face4.mat")
cube.SetMaterial(4, "assets/materials/face5.mat")
cube.SetMaterial(5, "assets/materials/face6.mat")
```
### Validate Geometry and create Node
After having determined the geometry, it's possible to validate your structure. If all is ok, you can create [Object] and [Node].
```python
if cube.Validate():
geo = plus.GetRenderSystem().CreateGeometry(cube,False)
obj = hg.Object()
obj.SetGeometry(geo)
node = hg.Node()
node.SetName("generated_cube")
transform = hg.Transform(hg.Vector3(0,3,0))
node.AddComponent(transform)
node.AddComponent(obj)
scene.AddNode(node)
return node
```

View File

@ -1,73 +0,0 @@
.title Installation
## Quick Install
* **Using PIP in a command line:** `pip install harfang`
* **Or download the wheel from :** [Downloads](https://www.harfang3d.com/downloads)
If anything goes wrong, please look at the [TroubleShooting](#TroubleShooting) section.<br/>
Further details on the installation are available below.
## Prerequisites
The following dependencies must be installed on your system for any Harfang project to work properly.
* Functional OpenGL 3.3 hardware and drivers
### Windows
* OpenAL redistributable (`oalinst.exe`)
* Visual C++ 2017 redistributable (`vcredist.exe`)
### Linux
* OpenAL (`sudo apt-get install libopenal1`)
## Installation
Harfang is available for several programming languages as an extension or as a standalone executable. The following sections describe the installation procedure for each variant.
### Python
* Download the `.whl` package for your OS and Python version. ([Downloads](https://www.harfang3d.com/downloads))
#### Windows
1. Open a command prompt as Administrator (`Win+X` then `Command Prompt (Admin)`).
1. Switch to the download directory and execute `pip install <your_harfang_version>.whl --user`.
#### OSX
1. Open a terminal window (in `Applications/Utilities/Terminal.app`).
1. Switch to the download directory and execute `pip install <your_harfang_version>.whl --user`.
#### Linux
1. Open a terminal window.
1. Switch to the download directory and execute `pip install <your_harfang_version>.whl --user`.
**Note:** You might need to explicitly use `pip3` to install the module if your system has both Python 2 and 3 installed.
#### Confirm your installation ####
Confirm your installation by starting your Python 3 interpreter and execute the following statement `import harfang as hg`. If you receive no error message, the installation was successful.
### Lua
Deploy the binary extension to your Lua interpreter or use the provided interpreter.
## <a name="Troubleshooting"></a>Troubleshooting
### Python
#### 1. `pip install` fails with a message saying `harfang is not a supported wheel on this platform`.
Make sure that your pip install is up to date. Outdated pip versions have been known to cause such problems.
#### 2. The dynamic library fails to load when importing the `harfang` module in Python.
Make sure your system has the required runtime dependencies installed. It should have OpenAL and on Windows the Visual C++ 2017 redistributable installed.
#### 3. `ImportError: DLL load failed: %1 is not a valid Win32 application.` error when importing the `harfang` module.
This error usually happens when installing the incorrect version of Harfang for your Python version. For example when installing the 64 bit version of Harfang on a 32 bit install of the Python interpreter.

View File

@ -2,7 +2,7 @@
Harfang is a high-level software library to create applications that display 2D/3D visuals and play sound/music.
It provides a unified API to write programs using different programming languages and is available for Windows, OSX and Linux (Debian/Ubuntu).
It provides a unified API to write programs using different programming languages and is available for Windows and Linux (for more details, please refer to the [man.Requirements]).
## Supported Programming Languages

View File

@ -23,19 +23,19 @@ The rigid body intertia tensor is computed from its collision shape properties.
## Simulating Physics
Create a physics backend such as [SceneNewtonPhysics] and call [SceneNewtonPhysics_SceneCreatePhysicsFromAssets] to create the physics states corresponding to the scene declaration.
Create a physics backend such as [SceneNewtonPhysics] and call [SceneBullet3Physics_SceneCreatePhysicsFromAssets] to create the physics states corresponding to the scene declaration.
*Note:* [SceneNewtonPhysics_SceneCreatePhysicsFromAssets] means that if setting up the physics states requires access to an external resource, such as a mesh, it should be loaded from the assets system. If you are working from the filesystem, use [SceneNewtonPhysics_SceneCreatePhysicsFromFile].
*Note:* [SceneBullet3Physics_SceneCreatePhysicsFromAssets] means that if setting up the physics states requires access to an external resource, such as a mesh, it should be loaded from the assets system. If you are working from the filesystem, use [SceneBullet3Physics_SceneCreatePhysicsFromFile].
### Running the Simulation
This involves 3 steps on each update:
1. Synchronize physics state with the scene declaration using [SceneNewtonPhysics_SceneCreatePhysicsFromAssets]. Alternatively, you can use a more fine-grained approach using [SceneNewtonPhysics_NodeCreatePhysicsFromAssets] to improve performance.
2. Step the simulation using [SceneNewtonPhysics_StepSimulation].
3. Synchronize the updated physics transformations to the scene using [SceneNewtonPhysics_SyncDynamicBodiesToScene].
1. Synchronize physics state with the scene declaration using [SceneBullet3Physics_SceneCreatePhysicsFromAssets]. Alternatively, you can use a more fine-grained approach using [SceneBullet3Physics_NodeCreatePhysicsFromAssets] to improve performance.
2. Step the simulation using [SceneBullet3Physics_StepSimulation].
3. Synchronize the updated physics transformations to the scene using [SceneBullet3Physics_SyncDynamicBodiesToScene].
*Note:* If you are using kinematic bodies you will also need to synchronize them from their node transformation on each update using [SceneNewtonPhysics_SyncKinematicBodiesFromScene].
*Note:* If you are using kinematic bodies you will also need to synchronize them from their node transformation on each update using [SceneBullet3Physics_SyncKinematicBodiesFromScene].
### The Easy Way
@ -45,7 +45,7 @@ When using a script system, this function will also dispatch collision events to
## Keeping the System Synchronized
Call the physics system garbage collect method (eg. [SceneNewtonPhysics_GarbageCollect]) on each update to ensure that destroyed nodes or components are properly removed. If you know that no node or component was destroyed during a particular update, not calling the garbage collector will save on performance.
Call the physics system garbage collect method (eg. [SceneBullet3Physics_GarbageCollect]) on each update to ensure that destroyed nodes or components are properly removed. If you know that no node or component was destroyed during a particular update, not calling the garbage collector will save on performance.
## Reading Physics Transformation

View File

@ -1,140 +0,0 @@
.title Post processing
Post processing occures after main scene rendering in order to add more realistic effects (motion blur, ambient occlusion...)
.img("post_process_pipeline.png")
## Post process
* [BloomPostProcess]
* [ChromaticDispersionPostProcess]
* [HSLPostProcess]
* [MotionBlurPostProcess]
* [RadialBlurPostProcess]
* [SAOPostProcess]
* [SharpenPostProcess]
### Usage (python)
All post-processings have the same init/remove procedures:
```
import harfang as hg
...
camera = scene.GetCurrentCamera()
post_process = hg.BloomPostProcess()
camera.AddComponent(post_process)
...
camera.RemoveComponent(post_process)
...
```
_In that exemple we use "BloomPostProcess", but it could be "ChromaticDispersionPostProcess", "HSLPostProcess", and so on..._
## Post process Stack
You can add as much PostProcessComponent as you like to the Camera.
It will be executed in the order of appearance in the Node's stack: this is the **Post Process stack**.
The order of execution of the post-processes is important:
.img("post_process_stack.png")
---
## BloomPostProcess
Drops a glow around enlighten areas. This effect enhances the impression of brightness.
_Bloom post-process:_
.img("bloom_01.png")
_No post-process:_
.img("no_post_process.png")
---
## ChromaticDispersionPostProcess
This filter works by independently offseting the red, green and blue components of the input image.
_Chromatic dispersion post-process:_
.img("chromatic_dispersion_01.png")
_No post-process:_
.img("no_post_process.png")
---
## HSLPostProcess
Post-process component implementing a Hue/Saturation/Brightness filter.
* **Hue:** add a circular shift to pixel colors.
* **Saturation:** set the colors strength (0: picture in grayscale).
* **Brightness:** Set the brightnes level (0 sets the screen to black). This can be used to fade-in / fade-out effect.
_HSL post-process:_
.img("HSL_01.png")
_No post-process:_
.img("no_post_process_camaro.png")
---
## MotioBlurPostProcess
This effect reproduce the famous cinematographic effect that blurs moving parts.
The faster the part, the blurrier it is. Motion-blur increases the realism of the rendering by softening the movements.
_Motion blur post-process:_
.img("motionblur_01.png")
_No post-process:_
.img("no_post_process_camaro.png")
---
## RadialBlurPostProcess
This effect blurs the pixels from a point of the screen. The further the pixels are from the point, the blurrier they are.
Unlike motion-blur, the radial-blur is independent of motion.
_Radial blur post-process:_
.img("radial_blur_01.png")
_No post-process:_
.img("no_post_process_camaro.png")
---
## SAOPostProcess
S.A.O for Screen-space Ambient Occlusion.
SAO is a fast real-time ambient occlusion rendering. It calculates pixels occlusions using the frame Z-Buffer.
It's an approximation of real ambient occlusion, but it's quite faster.
SAO is independant of scene complexity, as it works only on pixels datas (colors buffer & Z-Buffer).
_SAO post-process:_
.img("SAO_01.png")
_No post-process:_
.img("no_post_process_camaro.png")
---
## SharpenPostProcess
This effect reinforce contrasted edges using a convolution matrice.
_Sharpen post-process:_
.img("Sharpen_01.png")
_No post-process:_
.img("no_post_process.png")

View File

@ -2,11 +2,21 @@
## System Requirements
* **GPU:** Graphic card with OpenGL 3.3 support.
* **GPU:** Graphic card with OpenGL 3.3, Direct3D 11 or OpenGL ES 3.1 support.
* **CPU** and **memory** requirements are mostly dependent on your project characteristics.
A faster computer for development is recommended.
### Supported desktop OS
* Windows 7+, OSX 10.8+, Ubuntu 14.04+
* Windows 10+ (Intel)
* Ubuntu 20.04 LTS+ (Intel)
* Aarch Linux 64 (ARM)
### Window systems
* X11
* Wayland
### VR Support
* Via SteamVR (Windows only)

View File

@ -1 +0,0 @@
.title Toolchain

View File

@ -1,15 +0,0 @@
.title Assets folders
.tutorial(goal="Access to the file system through assets folders", level="Intermediate", duration=15, lang=All, group="Filesystem")
#### Python
```python
[import:tutorials/filesystem/1_assets_folder.py]
```
#### Lua
```lua
[import:tutorials/filesystem/1_assets_folder.lua]
```

View File

@ -1,15 +0,0 @@
.title Recursive walk
.tutorial(goal="Walk recursively though the content of a directory", level="Beginner", duration=5, lang=All, group="Filesystem")
#### Python
```python
[import:tutorials/filesystem/3_Recursive_directory_listing.py]
```
#### Lua
```lua
[import:tutorials/filesystem/3_Recursive_directory_listing.lua]
```

View File

@ -1,15 +0,0 @@
.title Basic GUI
.tutorial(goal="Create and display a basic GUI using ImGui", level="Beginner", duration=15, lang=All, group="GUI")
#### Python
```python
[import:tutorials/imgui/1_basic.py]
```
#### Lua
```lua
[import:tutorials/imgui/1_basic.lua]
```

View File

@ -1,15 +0,0 @@
.title Basic loop
.tutorial(goal="Basic immediate rendering loop", level="Beginner", duration=10, lang=All, group="Immediate rendering")
#### Python
```python
[import:tutorials/immediate/1_basic_loop.py]
```
#### Lua
```lua
[import:tutorials/immediate/1_basic_loop.lua]
```

View File

@ -1,15 +0,0 @@
.title Immediate scene
.tutorial(goal="Immediate rendering of a scene without a pipeline", level="Beginner", duration=10, lang=All, group="Immediate rendering")
#### Python
```python
[import:tutorials/immediate/3_scene_no_pipeline.py]
```
#### Lua
```lua
[import:tutorials/immediate/3_scene_no_pipeline.lua]
```

View File

@ -1,15 +0,0 @@
.title List devices
.tutorial(goal="List the input devices", level="Beginner", duration=10, lang=All, group="Input")
#### Python
```python
[import:tutorials/input/1_list_devices.py]
```
#### Lua
```lua
[import:tutorials/input/1_list_devices.lua]
```

View File

@ -1,15 +0,0 @@
.title Input pad
.tutorial(goal="How to read values from the joypad - Using Joypad object", level="Beginner", duration=10, lang=All, group="Input")
#### Python
```python
[import:tutorials/input/8_read_pad.py]
```
#### Lua
```lua
[import:tutorials/input/8_read_pad.lua]
```

View File

@ -1,15 +0,0 @@
.title Input pad 2
.tutorial(goal="How to read values from the gamepad - Using hg.ReadGamepad", level="Beginner", duration=10, lang=All, group="Input")
#### Python
```python
[import:tutorials/input/9_read_pad_2.py]
```
#### Lua
```lua
[import:tutorials/input/9_read_pad_2.lua]
```

View File

@ -1,15 +0,0 @@
.title Read keyboard
.tutorial(goal="How to read from the keyboard", level="Beginner", duration=10, lang=All, group="Input")
#### Python
```python
[import:tutorials/input/2_read_keyboard.py]
```
#### Lua
```lua
[import:tutorials/input/2_read_keyboard.lua]
```

View File

@ -1,15 +0,0 @@
.title Read keyboard 2
.tutorial(goal="How to read from the keyboard - Using hg.ReadKeybard('default') function", level="Beginner", duration=10, lang=All, group="Input")
#### Python
```python
[import:tutorials/input/3_read_keyboard_2.py]
```
#### Lua
```lua
[import:tutorials/input/3_read_keyboard_2.lua]
```

View File

@ -1,15 +0,0 @@
.title Read keyboard 3
.tutorial(goal="How to read from the keyboard - Using hg.ReadKeyboard('raw') function", level="Beginner", duration=10, lang=All, group="Input")
#### Python
```python
[import:tutorials/input/4_read_keyboard_3.py]
```
#### Lua
```lua
[import:tutorials/input/4_read_keyboard_3.lua]
```

View File

@ -1,15 +0,0 @@
.title Read mouse
.tutorial(goal="How to read values from the mouse - Using Mouse object", level="Beginner", duration=10, lang=All, group="Input")
#### Python
```python
[import:tutorials/input/5_read_mouse.py]
```
#### Lua
```lua
[import:tutorials/input/5_read_mouse.lua]
```

View File

@ -1,15 +0,0 @@
.title Read mouse 2
.tutorial(goal="How to read values from the mouse - Using hg.ReadMouse", level="Beginner", duration=10, lang=All, group="Input")
#### Python
```python
[import:tutorials/input/6_read_mouse_2.py]
```
#### Lua
```lua
[import:tutorials/input/6_read_mouse_2.lua]
```

View File

@ -1,15 +0,0 @@
.title Read mouse 3
.tutorial(goal="How to read values from the mouse - Using hg.ReadMouse('raw')", level="Beginner", duration=10, lang=All, group="Input")
#### Python
```python
[import:tutorials/input/7_read_mouse_3.py]
```
#### Lua
```lua
[import:tutorials/input/7_read_mouse_3.lua]
```

View File

@ -1,15 +0,0 @@
.title Physics cubes
.tutorial(goal="Add and remove many physics objects", level="Intermediate", duration=10, lang=All, group="Physics")
#### Python
```python
[import:tutorials/physics/2_physics_cubes.py]
```
#### Lua
```lua
[import:tutorials/physics/2_physics_cubes.lua]
```

View File

@ -1,15 +0,0 @@
.title Impulse
.tutorial(goal="Apply an impulse to a rigid body", level="Intermediate", duration=10, lang=All, group="Physics")
#### Python
```python
[import:tutorials/physics/1_impulse.py]
```
#### Lua
```lua
[import:tutorials/physics/1_impulse.lua]
```

View File

@ -1,15 +0,0 @@
.title Physics overrides matrix
.tutorial(goal="Physics overrides Transform's matrix", level="Intermediate", duration=10, lang=All, group="Physics")
#### Python
```python
[import:tutorials/physics/3_test_physics_overrides_matrix.py]
```
#### Lua
```lua
[import:tutorials/physics/3_test_physics_overrides_matrix.lua]
```

View File

@ -1,15 +0,0 @@
.title Load picture
.tutorial(goal="Load a picture", level="Beginner", duration=5, lang=All, group="Picture")
#### Python
```python
[import:tutorials/picture/1_load_picture.py]
```
#### Lua
```python
[import:tutorials/picture/1_load_picture.py]
```

View File

@ -1,15 +0,0 @@
.title Save picture
.tutorial(goal="Save a picture", level="Beginner", duration=5, lang=All, group="Picture")
#### Python
```python
[import:tutorials/picture/2_save_picture.py]
```
#### Lua
```python
[import:tutorials/picture/2_save_picture.py]
```

View File

@ -1,15 +0,0 @@
.title Dynamics objects
.tutorial(goal="Render and animate a large amount of objects", level="Beginner", duration=15, lang=All, group="Scene")
#### Python
```python
[import:tutorials/scene/2_many_dynamics_objects.py]
```
#### Lua
```lua
[import:tutorials/scene/2_many_dynamics_objects.lua]
```

View File

@ -1,15 +0,0 @@
.title Physics kapla shooting
.tutorial(goal="Shoot boulders on a physics kapla tower", level="Intermediate", duration=30, lang=All, group="Scene")
#### Python
```python
[import:tutorials/scene/5_kapla_shooting.py]
```
#### Lua
```lua
[import:tutorials/scene/5_kapla_shooting.lua]
```

View File

@ -1,15 +0,0 @@
.title Physics kapla tower
.tutorial(goal="Physics simulation of a Kapla tower", level="Intermediate", duration=30, lang=All, group="Scene")
#### Python
```python
[import:tutorials/scene/3_scene_kapla_tower.py]
```
#### Lua
```lua
[import:tutorials/scene/3_scene_kapla_tower.lua]
```

View File

@ -1,15 +0,0 @@
.title Light priority
.tutorial(goal="How light priority works", level="Beginner", duration=10, lang=All, group="Scene")
#### Python
```python
[import:tutorials/scene/6_light_priority.py]
```
#### Lua
```lua
[import:tutorials/scene/6_light_priority.lua]
```

View File

@ -1,15 +0,0 @@
.title Scene multi viewports
.tutorial(goal="Split the display of a scene in several viewports", level="Beginner", duration=10, lang=All, group="Scene")
#### Python
```python
[import:tutorials/scene/4_multi_viewport.py]
```
#### Lua
```lua
[import:tutorials/scene/4_multi_viewport.lua]
```

View File

@ -1,15 +0,0 @@
.title Scene
.tutorial(goal="Setup and render a 3D scene with the forward pipeline", level="Beginner", duration=10, lang=All, group="Scene")
#### Python
```python
[import:tutorials/scene/1_scene.py]
```
#### Lua
```lua
[import:tutorials/scene/1_scene.lua]
```

View File

@ -1,5 +0,0 @@
.title Tutorials
The following tutorials demonstrate usage of the Harfang API. A complete archive of the tutorials and their associated datas can be downloaded from [GitHub](https://github.com/harfang3d/tutorials-hg2/releases).
%TutorialIndex%

View File

@ -1,46 +0,0 @@
.title Writing a graphic application
There many ways to write a graphic application using the library. Depending the needs of your application one approach might be much better suited than the others. The following options are available:
Note: You can find many examples of graphic applications in the [man.Tutorials].
## Renderer-only application
This is the most low-level application where most manual work is required. But for very specific needs it might make much more sense to directly use the renderer instead of trying to bend the [RenderSystem] or even a [Scene] to achieve your goals.
This type of application is advised if you:
* Need to render a lot of custom primitives or very dynamic content,
* Do not require complex rendering functionalities such as shadows,
* Do not need scene functionalities such as animation or scripts,
* Have sufficient knowledge to work at such a low-level.
## RenderSystem application
The [RenderSystem] without a [Scene] is mostly useful for the high-level drawing code it provides over the [Renderer] API. It comes at the cost of having to bundle the core resources package and, as with most high-level APIs, somewhat reduced performances and higher memory consumption.
This type of application is advised if you:
* Need to render a moderate amount of standard primitives with common attributes,
* Do not require complex rendering functionalities such as shadows,
* Do not need scene functionalities such as animation or scripts.
## Scene application
Applications making use of a [Scene] object can leverage the full set of functionalities the engine has to offer. Complete scene management extensible with Lua scripts ([man.ScriptComponent]), support for advanced rendering features such as hardware skinning, shadow-mapping or post-processing.
Using a scene also automatically provides multi-threading benefits as the engine has knowledge of most your application graphical objects and can manage them more efficiently.
This type of application is advised if you:
* Need to display complex world efficiently with the typical feature set of real time modern 3d applications,
## Plus application
The [Plus] API is a high-level wrapper over the Harfang API. It simplifies the use of all previously mentionned APIs and is usually a good starting point for any project.
It is however very limited in scope and complex requirements will usually require dealing directly with the low-level APIs.
## Mixing application types
Since all of the previously described approaches are build on the top of each other ([Scene] is renderer by the [RenderSystem] through [Renderer] with [Plus] wrapping all of those APIs) it is safe to mix different approaches to build an application.

View File

@ -29,10 +29,3 @@ man.Scripting
man.Navigation
man.VR
man.Classes
man.Functions
man.Constants
man.Enums
man.Tutorials

View File

@ -1,34 +0,0 @@
from PyQt5.QtWidgets import QApplication
from doc_editor.main_window import MainWindow
import sys
import os
import argparse
if __name__ == '__main__':
parser = argparse.ArgumentParser(description="Internal documentation editor")
parser.add_argument('--api_path', type=str, help="API path", required=False)
parser.add_argument('--doc_path', type=str, help="Documentation path", required=False)
parser.add_argument('--out_path', type=str, help="Documentation output path", required=False)
args = parser.parse_args()
app = QApplication(sys.argv)
path = os.path.dirname(os.path.realpath(sys.argv[0]))
main_window = MainWindow()
main_window.preview_css = os.path.join(path, "doc_editor", "markdown.css")
if args.api_path:
main_window.load_api(args.api_path)
if args.doc_path:
main_window.load_doc(args.doc_path)
if args.out_path:
main_window.build_documentation(args.out_path)
r = 0
else:
main_window.showMaximized()
r = app.exec_()
sys.exit(r)

View File

@ -1 +0,0 @@
python doc_to_html.py --api_path api.xml --doc_path doc.xml --out_path doc_html

View File

@ -1,502 +0,0 @@
import doc_utils.doc_tools as doc_tools
import doc_utils.api_tools as api_tools
import doc_utils.html_tools as html_tools
import search_index
from functools import partial
import argparse
import shutil
import sys
import os
import datetime
from collections import OrderedDict
gen_online_doc = None
version = "0.0.0"
def get_element_output_path(output_path, uid, ext='.html'):
return os.path.join(output_path, uid + ext)
def html_link_formatter(output_path, uid, is_img_link=False):
if is_img_link:
if gen_online_doc:
return "/documentations/%s/img/%s" % (version, uid)
return "img/" + uid
link, name, hint = get_element_output_path('', uid), uid, None
if uid in doc_tools.man:
return "[%s](%s)" % (doc_tools.get_element_title(uid), link)
if uid in api_tools.api:
tag = api_tools.api[uid][0]
parent = api_tools.api_parent_map[tag]
def format_enum_values(tag):
values = [val.get('name') for val in tag.iter('entry')]
return doc_tools.list_to_natural_string(values, "or")
def format_constants_values(tag):
values = [val.get('name') for val in tag.iter('entry')]
return doc_tools.list_to_natural_string(values, "and")
if tag.get("global") == "1": # global symbol link
global_type_pages = {"function": "man.Functions.html", "enum": "man.Enums.html", "constants": "man.Constants.html"}
if tag.tag in global_type_pages:
link = "%s#%s" % (global_type_pages[tag.tag], uid)
name = tag.get("name")
if tag.tag == "enum":
hint = format_enum_values(tag)
elif tag.tag == "constants":
hint = format_constants_values(tag)
else:
if parent.tag == "class":
parent_uid = parent.get("uid")
link = "%s.html#%s" % (parent_uid, uid)
name = tag.get("name")
hint = "%s.%s" % (parent.get("name"), name)
if tag.tag == "enum":
hint += ' : ' + format_enum_values(tag)
if hint:
path = '<a href="%s" title="%s">%s</a>' % (link, hint, name)
else:
path = '<a href="%s">%s</a>' % (link, name)
return path
def get_header(uid):
if not gen_online_doc:
title = 'Documentation'
if uid in doc_tools.man:
title = doc_tools.get_element_title(uid)
return '<h1>%s</h1>' % title
return ""
def get_footer(uid):
return '<hr><small id="version-footer">%s %s documentation. Generated %s.</small></hr>\n' % (args.project_name, version, datetime.datetime.today().strftime('%c'))
def format_complete_html_man_page(uid, body, header=get_header, footer=get_footer):
if not gen_online_doc:
html = '<html>\n'
html += '<head><meta charset="UTF-8"><link type="text/css" rel="stylesheet" href="markdown.css"></head>\n'
html += '<body>\n'
if header:
html += header(uid)
html += body
if footer:
html += footer(uid)
html += '</body>\n'
html += '</html>\n'
return html
html = ''
if header:
html += header(uid)
return html + body
def format_html_link(text, url):
if text in api_tools.api:
text = '<span class="text-default">%s</span>' % text
return '<a href="%s">%s</a>' % (url, text)
def format_html_breadcrumb(breadcrumb):
# convert from uid to HTML link
return ''
if len(breadcrumb) < 2:
if gen_online_doc:
return '<div class="doc-breadcrumb"><p></p></div>\n'
return '' # do not output empty breadcrumb
links = []
# for uid in reversed(breadcrumb[1:]):
for uid in reversed(breadcrumb):
title = doc_tools.get_element_title(uid)
path = get_element_output_path('', uid)
links.append(format_html_link(title, path))
# links.append(doc_tools.get_element_title(breadcrumb[0]))
return '<div markdown=1 class="doc-breadcrumb">%s</div>' % ' &gt; '.join(links) # offline breadcrumb
def get_class_header(uid):
breadcrumb = doc_tools.build_man_page_breadcrumb(man_tree, 'man.Classes')
breadcrumb.insert(0, uid)
return get_header(uid) + format_html_breadcrumb(breadcrumb)
def get_enum_header(uid):
breadcrumb = doc_tools.build_man_page_breadcrumb(man_tree, 'man.ScriptReference')
breadcrumb.insert(0, uid)
return get_header(uid) + format_html_breadcrumb(breadcrumb)
def get_man_header(uid):
breadcrumb = doc_tools.build_man_page_breadcrumb(man_tree, uid)
return get_header(uid) + format_html_breadcrumb(breadcrumb)
get_header_fn = {
'class': get_class_header,
'enum': get_enum_header
}
def save_page(output_path, uid, html):
with open(get_element_output_path(output_path, uid), 'w', encoding='utf-8') as file:
file.write(html)
# ------------------------------------------------------------------------------
man_tree = None
def build_doc_tree():
# build the final documentation tree
tree = OrderedDict()
def insert_in_tree(uid):
if uid not in man_tree: # insert root UID
if uid not in tree:
tree[uid] = OrderedDict()
return tree[uid]
sub_tree = insert_in_tree(man_tree[uid])
if uid not in sub_tree:
sub_tree[uid] = OrderedDict()
return sub_tree[uid]
for uid in man_tree:
insert_in_tree(uid)
if True:
# populate custom pages
def insert_in_uid_dict(uid, uids):
dict = insert_in_tree(uid)
for uid in uids:
if uid not in dict:
dict[uid] = {}
insert_in_uid_dict("man.Classes", doc_tools.get_all_classes())
insert_in_uid_dict("man.Functions", sorted(html_tools.get_tag_uids("function", True)))
insert_in_uid_dict("man.Enums", sorted(html_tools.get_tag_uids("enum", True)))
return tree
def output_tree_html(path):
""" Obsolete function that creates the documentation tree automatically """
tree = build_doc_tree()
with open(path, 'w') as file:
def output_tree(tree, depth):
for uid, sub_tree in tree.items():
title = doc_tools.get_element_title(uid)
if depth == 0:
file.write('<li class="first">\n')
else:
file.write('<li>\n')
file.write('<a href="%s"><abbr title="%s">%s</abbr></a>\n' % (uid + ".html", title, title))
if len(sub_tree) > 0:
file.write('<ul>\n')
output_tree(sub_tree, depth+1)
file.write('</ul>\n')
file.write('</li>\n')
file.write('<ul id="tree" class="tree doc-index">\n')
output_tree(tree, 0)
file.write('</ul>\n')
return True
def create_tree_html(path):
""" New function to create the documentation tree from a simple input file """
with open(os.path.join(args.doc_path, "tree_desc.txt"), "r", encoding="utf-8") as file:
tree_lines = file.read().splitlines()
class Node:
def __init__(self, name):
self.name = name
self.children = []
def get_link(self):
return self.name
def __repr__(self):
return 'NODE %s' % self.name
def to_html(self):
if self.name == '':
return '<br>\n'
str = '<li>'
str += self.get_link()
if len(self.children) > 0:
str += '<ul>\n'
for child in self.children:
str += child.to_html()
str += '</ul>\n'
str += '</li>\n'
return str
class Link(Node):
def __init__(self, link):
super().__init__(link)
def get_link(self):
name = doc_tools.get_element_title(self.name)
if gen_online_doc:
return '<a href="%s">%s</a>' % (self.name + '.html', name)
return '<a href="%s" target="content-frame">%s</a>' % (self.name + '.html', name)
def __repr__(self):
return 'LINK %s' % self.name
last_node = Link('man.Pyindex')
stack = [last_node]
for line in tree_lines:
current_depth = len(stack)
# determine target depth
target_depth = 0
while line[target_depth:target_depth+1] == '\t':
target_depth += 1
target_depth += 1
# create the new node
decl = line[target_depth-1:]
if decl.startswith("!"):
node = Node(decl[1:])
else:
node = Link(decl)
# make sure we only go down one level at a time
assert target_depth <= current_depth + 1
if target_depth > current_depth:
stack.append(last_node)
elif target_depth < current_depth:
while target_depth < len(stack):
stack.pop()
stack[-1].children.append(node)
last_node = node
# output final tree
with open(path, "w", encoding="utf-8") as file:
if not gen_online_doc:
file.write('<html>\n')
file.write('<head><link type="text/css" rel="stylesheet" href="markdown.css"></head>\n')
file.write('<body>\n')
file.write('<h1>%s %s</h1>' % (args.project_name, version))
file.write('<ul id="tree" class="tree doc-index">')
for child in stack[0].children: # skip root entry
file.write(child.to_html())
file.write('</ul>')
if not gen_online_doc:
file.write('</body>\n')
file.write('</html>\n')
def sanity_check():
report = {
'missing': {},
'obsolete': [],
'missing_pages': [],
'orphan_pages': []
}
ok = True
for uid in doc_tools.doc.keys():
if not uid in api_tools.api:
report['obsolete'].append(uid)
ok = ok and report['obsolete']
for uid, tag in api_tools.api.items():
if not uid in doc_tools.doc:
typename = tag[0].tag
if not typename in report['missing']:
report['missing'][typename] = []
report['missing'][typename].append(uid)
ok = ok and report['missing']
link_list = ['man.Index']
for uid in doc_tools.man.keys():
for link in doc_tools.gather_manual_links(uid):
filename = '{0}.md'.format(link)
link_list.append(link)
if not os.path.isfile(os.path.join(args.doc_path, filename)):
report['missing_pages'].append(link)
ok = ok and report['missing_pages']
with open(os.path.join(args.doc_path, "tree_desc.txt"), "r", encoding="utf-8") as file:
tree_lines = file.read().splitlines()
for line in tree_lines:
line = line.strip()
if(line.startswith('!')):
continue
link_list.append(line)
for uid in doc_tools.man.keys():
if not uid in link_list:
report['orphan_pages'].append(uid)
ok = ok and report['orphan_pages']
report['missing_pages'].sort()
report['orphan_pages'].sort()
return (ok, report)
def save_sanity_check_report(path, report):
with open(path, "w", encoding="utf-8") as file:
file.write('# Error report\n')
if report['missing']:
file.write(' * [missing](#missing) : undocumented symbols.\n')
for typename, items in report['missing'].items():
if not items:
continue
file.write(' * [{0}](#{1})\n'.format(typename, typename))
if report['obsolete']:
file.write(' * [obsolete](#obsolete) : cannot find the symbol in the api. \n')
if report['missing_pages']:
file.write(' * [missing pages](#missing-pages) : broken link\n')
if report['orphan_pages']:
file.write(' * [orphan pages](#orphan-pages) : cannot find a reference to this file.\n')
if report['missing']:
file.write('## missing\n')
for typename, items in report['missing'].items():
if not items:
continue
file.write('### {0}\n'.format(typename))
for uid in items:
file.write(' * {0}\n'.format(uid))
if report['obsolete']:
file.write('## obsolete\n')
for uid in report['obsolete']:
file.write(' * {0}\n'.format(uid))
if report['missing_pages']:
file.write('## missing pages\n')
for uid in report['missing_pages']:
file.write(' * {0}\n'.format(uid))
if report['orphan_pages']:
file.write('## orphan pages\n')
for uid in report['orphan_pages']:
file.write(' * {0}\n'.format(uid))
def doc_to_html(output_path, css=None, whitelist=None, callback=None):
"""Convert the complete documentation to HTML"""
os.makedirs(output_path, exist_ok = True)
link_formatter = partial(html_link_formatter, output_path)
# gather symbol pages
doc_pages = []
for uid, tag in api_tools.api.items():
if whitelist is None or uid in whitelist:
if tag[0].tag in ['class']:
doc_pages.append((uid, tag))
# gather manual pages
man_pages = []
for uid, data in doc_tools.man.items():
if whitelist is None or uid in whitelist:
man_pages.append((uid, data))
page_count = len(doc_pages) + len(man_pages)
# generate manual pages hierarchy tree
tree_blacklist = []
global man_tree
man_tree = doc_tools.generate_manual_tree(tree_blacklist)
create_tree_html(os.path.join(output_path, "tree.html"))
# generate all pages
page_generated = 0
for uid, tag in doc_pages:
type = tag[0].tag
if callback and not callback(uid, page_generated, page_count):
return False
data = doc_tools.get_content_always(uid)
body = html_tools.format_page_content(uid, data, link_formatter)
html = format_complete_html_man_page(uid, body, get_header_fn[type])
save_page(output_path, uid, html)
search_index.parse(uid, version, html)
page_generated += 1
for uid, data in man_pages:
body = html_tools.format_page_content(uid, data, link_formatter)
html = format_complete_html_man_page(uid, body, get_man_header)
save_page(output_path, uid, html)
search_index.parse(uid, version, html)
page_generated += 1
# copy css
if css is not None:
shutil.copyfile(css, os.path.join(output_path, 'markdown.css'))
search_index.save(output_path, "search_index.json")
man_tree = None
return True
# ------------------------------------------------------------------------------
if __name__ == '__main__':
parser = argparse.ArgumentParser(description="Convert the internal documentation format to HTML")
parser.add_argument('--project_name', type=str, help="Project name", required=True)
parser.add_argument('--api_path', type=str, help="API path", required=True)
parser.add_argument('--doc_path', type=str, help="Documentation path", required=True)
parser.add_argument('--out_path', type=str, help="Output folder", required=True)
parser.add_argument('--uid', type=str, help="Generate the documentation for this specific UID")
parser.add_argument('--version', type=str, help="API version")
parser.add_argument('--online', action="store_true", help="Generate the online documentation")
args = parser.parse_args()
gen_online_doc = args.online
html_tools.gen_online_doc = gen_online_doc
if args.version: version = args.version
# determine CSS location
path = os.path.dirname(os.path.realpath(sys.argv[0]))
css = os.path.join(path, "markdown.css")
# load the API and documentation
api_tools.load_api(args.api_path)
doc_tools.load_doc_folder(args.doc_path)
# generate documentation
whitelist = None if args.uid is None else args.uid.split(',')
doc_to_html(args.out_path, css, whitelist)
ok, report = sanity_check()
save_sanity_check_report(os.path.join(args.out_path, 'sanity_report.md'), report)

View File

@ -1,7 +1,7 @@
import os
import re
import argparse
import datetime
import shutil
import xml.etree.ElementTree as ETree
import doc_utils.doc_tools as doc_tools
@ -430,8 +430,7 @@ def convert(api, doc, out):
if page == '':
man_pages_spacing.append(man_pages[-1])
else:
if page not in ['man.Classes', 'man.Constants', 'man.Functions', 'man.Enums', 'man.Tutorials']:
man_pages.append(page)
man_pages.append(page)
for page in man_pages:
parse_man_page(page)
@ -590,6 +589,9 @@ if __name__ == '__main__':
parser.add_argument('--version', type=str, help="Documentation version", required=True)
args = parser.parse_args()
static_img = os.path.join(args.out, '..', 'static', 'images', 'docs', args.version)
shutil.copytree('img', static_img)
with open(args.api, "r") as file:
api = ETree.fromstring(file.read())

Binary file not shown.

Before

Width:  |  Height:  |  Size: 290 KiB

After

Width:  |  Height:  |  Size: 202 KiB

View File

@ -1,169 +0,0 @@
from bs4 import BeautifulSoup
import json
import os
index = []
def get_soup_title_and_category(uid, soup):
if uid == 'man.Functions':
uid = uid
title, category = None, 'other'
tutorial_header = soup.find('table', class_='tutorial-header')
is_tutorial = tutorial_header is not None
#
if title is None:
doc_details = soup.find('div', class_='doc-details')
if doc_details is not None:
h1 = doc_details.find('h1')
if h1 is not None:
title = str(h1.text)
if title is None:
breadcrumb = soup.find('div', class_='doc-breadcrumb')
if breadcrumb is not None:
links = breadcrumb.find_all('a')
if len(links) > 0:
title = str(links[-1].string)
else:
title = None
else:
h1 = soup.find('h1')
if h1 is not None:
title = h1.string
if title is not None:
title = str(title)
if title is None or title == 'Documentation':
title = uid # fallback to uid
if is_tutorial:
title = "Tutorial '%s'" % title
# determine category
if is_tutorial:
category = 'tutorial'
elif uid.startswith('man.'):
category = 'manual'
elif title.endswith('Class'):
category = 'class'
title = title[:-5].rstrip()
return title, category
def filter_and_parse(uid, version, html, filter):
soup = BeautifulSoup(html, 'html.parser')
# get title and category
title, category = get_soup_title_and_category(uid, soup)
# apply filter
soup, body = filter(soup)
if body == '':
return
# build excerpt candidates
excerpts = []
def add_excerpt(ex):
if ex is None:
return
s = str(ex).strip()
if len(s) > 0:
excerpts.append(s)
for p in soup.find_all('p'): # raw paragraph content
add_excerpt(p.string)
for div in soup.find_all('div'): # function documentation
if 'class' in div.attrs:
for class_ in div['class']:
if class_ in ['function_doc']:
add_excerpt(div.string)
# finalize entry
entry = {'uid': uid, 'category': category, 'title': title, 'body': body, 'excerpts': excerpts, 'version': str(version)}
index.append(entry)
return soup, title
def clean_text(t):
return t.lstrip().rstrip()
def extract_page_functions(uid, version, page_title, soup):
function_divs = soup.find_all('div', class_='function_div')
for function_div in function_divs:
id = function_div.get('id')
if id.startswith(uid):
name = id[len(uid)+1:]
title = '%s.%s' % (uid, name)
else:
name = id
title = page_title
body = name
function_proto = function_div.find('div', class_='function_proto')
function_doc = function_div.find('div', class_='function_doc')
excerpt = []
if function_doc:
excerpt.append(clean_text(function_doc.text))
entry = {'uid': '%s#%s' % (uid, id), 'category': 'function', 'title': title, 'body': body, 'excerpts': excerpt, 'version': str(version)}
index.append(entry)
def parse(uid, version, html):
def basic_stripper_filter(soup):
# strip breadcrumb
breadcrumb = soup.find('div', {'class': 'doc-breadcrumb'})
if breadcrumb is not None:
breadcrumb.extract()
# strip version footer
version_span = soup.find('small', {'id': 'version-footer'})
if version_span is not None:
version_span.extract()
code_divs = soup.find_all('div', {'class': 'codehilite'})
for div in code_divs:
div.extract()
# extract body
body = soup.get_text(separator=' ')
# body = ' '.join(body.split())
for s in ['(', '[', '{', '\n']:
body = body.replace(s + ' ', s)
for s in [')', ']', '}', ',', ':', ';', '\n']:
body = body.replace(' ' + s, s)
for i in range(4):
body = body.replace(' ', ' ')
body = body.replace('\n\n', '\n')
return soup, body
soup, title = filter_and_parse(uid, version, html, basic_stripper_filter)
# extract page functions
extract_page_functions(uid, version, title, soup)
def save(dir, path):
with open(os.path.join(dir, path), 'w') as file:
for entry in index:
file.write('{"index":{}}\n')
json.dump(entry, file)
file.write('\n')
file.write('{"index":{}}\n')

View File

@ -112,7 +112,7 @@ Process::id_type Process::open(const string_type &command, const string_type &pa
#endif
const std::wstring wpath=utf8_to_wstring(path);
BOOL bSuccess = CreateProcess(nullptr, process_command.empty()?nullptr:&process_command[0], nullptr, nullptr, TRUE, 0,
BOOL bSuccess = CreateProcess(nullptr, process_command.empty()?nullptr:&process_command[0], nullptr, nullptr, TRUE, CREATE_NO_WINDOW,
nullptr, wpath.empty()?nullptr:wpath.c_str(), &startup_info, &process_info);
if(!bSuccess)

View File

@ -16,9 +16,9 @@ if(HG_BUILD_DOCS)
configure_file(doxyfile.tpl ${CMAKE_CURRENT_BINARY_DIR}/doxyfile @ONLY)
add_custom_target(doc_cppsdk ALL
${CMAKE_COMMAND} -E make_directory ${CMAKE_INSTALL_PREFIX}/cppsdk_docs
COMMAND ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/doxyfile
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
COMMENT "Generating CPPSDK documentation"
VERBATIM
COMMAND ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/doxyfile
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
COMMENT "Generating CPPSDK documentation"
VERBATIM
)
endif()

View File

@ -19,12 +19,20 @@ static AAABlur _CreateAAABlur(const Reader &ir, const ReadProvider &ip, const ch
aaa_blur.u_sigma = bgfx::createUniform("u_sigma", bgfx::UniformType::Vec4);
aaa_blur.u_input = bgfx::createUniform("u_input", bgfx::UniformType::Sampler);
aaa_blur.u_attr0 = bgfx::createUniform("u_attr0", bgfx::UniformType::Sampler);
if (!IsValid(aaa_blur)) {
DestroyAAABlur(aaa_blur);
}
return aaa_blur;
}
AAABlur CreateAAABlurFromFile(const char *path) { return _CreateAAABlur(g_file_reader, g_file_read_provider, path); }
AAABlur CreateAAABlurFromAssets(const char *path) { return _CreateAAABlur(g_assets_reader, g_assets_read_provider, path); }
bool IsValid(const AAABlur &aaa_blur) {
return bgfx::isValid(aaa_blur.compute) && bgfx::isValid(aaa_blur.u_dir) && bgfx::isValid(aaa_blur.u_sigma) && bgfx::isValid(aaa_blur.u_input) &&
bgfx::isValid(aaa_blur.u_attr0);
}
void DestroyAAABlur(AAABlur &aaa_blur) {
bgfx_Destroy(aaa_blur.compute);
bgfx_Destroy(aaa_blur.u_dir);
@ -34,6 +42,7 @@ void DestroyAAABlur(AAABlur &aaa_blur) {
}
void ComputeAAABlur(bgfx::ViewId &view_id, const iRect &rect, const Texture &attr0, bgfx::FrameBufferHandle fb0, bgfx::FrameBufferHandle fb1, const AAABlur &aaa_blur) {
__ASSERT__(IsValid(aaa_blur));
bgfx::TransientIndexBuffer idx;
bgfx::TransientVertexBuffer vtx;
CreateFullscreenQuad(idx, vtx);

View File

@ -23,4 +23,6 @@ void DestroyAAABlur(AAABlur &aaa_blur);
void ComputeAAABlur(bgfx::ViewId &view_id, const iRect &rect, const Texture &attr0, bgfx::FrameBufferHandle fb0,
bgfx::FrameBufferHandle fb1, const AAABlur &aaa_blur);
bool IsValid(const AAABlur &aaa_blur);
} // namespace hg

View File

@ -43,15 +43,28 @@ static bool LoadShaders(Bloom &bloom, const Reader &ir, const ReadProvider &ip,
static const uint64_t g_bloom_tex_flags = 0 | BGFX_TEXTURE_RT | BGFX_SAMPLER_U_CLAMP | BGFX_SAMPLER_V_CLAMP;
bool IsValid(const Bloom &bloom) {
return bgfx::isValid(bloom.in_fb) && bgfx::isValid(bloom.out_fb) && bgfx::isValid(bloom.u_source) && bgfx::isValid(bloom.u_input) &&
bgfx::isValid(bloom.u_params) && bgfx::isValid(bloom.u_source_rect) && bgfx::isValid(bloom.prg_threshold) && bgfx::isValid(bloom.prg_downsample) &&
bgfx::isValid(bloom.prg_upsample) && bgfx::isValid(bloom.prg_combine);
}
static Bloom CreateBloom(const Reader &ir, const ReadProvider &ip, const char *path, bgfx::BackbufferRatio::Enum ratio) {
Bloom bloom;
if (!LoadShaders(bloom, ir, ip, path)) {
DestroyBloom(bloom);
return bloom;
}
bloom.in_fb = bgfx::createFrameBuffer(ratio, bgfx::TextureFormat::RGBA16F, g_bloom_tex_flags);
bgfx::setName(bloom.in_fb, "Bloom IN FB");
bloom.out_fb = bgfx::createFrameBuffer(ratio, bgfx::TextureFormat::RGBA16F, g_bloom_tex_flags);
bgfx::setName(bloom.out_fb, "Bloom OUT FB");
if (!(bgfx::isValid(bloom.in_fb) && bgfx::isValid(bloom.out_fb))) {
DestroyBloom(bloom);
return bloom;
}
LoadShaders(bloom, ir, ip, path);
bgfx::setName(bloom.in_fb, "Bloom IN FB");
bgfx::setName(bloom.out_fb, "Bloom OUT FB");
return bloom;
}
@ -75,6 +88,8 @@ void DestroyBloom(Bloom &bloom) {
void ApplyBloom(bgfx::ViewId &view_id, const iRect &rect, const hg::Texture &input, bgfx::FrameBufferHandle output, const Bloom &bloom, float threshold,
float smoothness, float intensity) {
__ASSERT__(IsValid(bloom));
const bgfx::Caps *caps = bgfx::getCaps();
bgfx::TransientIndexBuffer idx;

View File

@ -34,4 +34,6 @@ void DestroyBloom(Bloom &bloom);
void ApplyBloom(bgfx::ViewId &view_id, const iRect &rect, const hg::Texture &input, bgfx::FrameBufferHandle output, const Bloom &bloom, float threshold,
float smoothness, float intensity);
bool IsValid(const Bloom &bloom);
} // namespace hg

View File

@ -887,6 +887,12 @@ void RigidBody::SetFriction(float friction) {
if (scene_ref && scene_ref->scene)
scene_ref->scene->SetRigidBodyFriction(ref, friction);
}
float RigidBody::GetRollingFriction() const { return scene_ref && scene_ref->scene ? scene_ref->scene->GetRigidBodyRollingFriction(ref) : 0.f; }
void RigidBody::SetRollingFriction(float rolling_friction) {
if (scene_ref && scene_ref->scene)
scene_ref->scene->SetRigidBodyRollingFriction(ref, rolling_friction);
}
//
bool Collision::IsValid() const { return scene_ref && scene_ref->scene ? scene_ref->scene->IsValidCollisionRef(ref) : false; }
@ -898,6 +904,13 @@ void Collision::SetType(CollisionType type) {
scene_ref->scene->SetCollisionType(ref, type);
}
Mat4 Collision::GetLocalTransform() const { return scene_ref && scene_ref->scene ? scene_ref->scene->GetCollisionLocalTransform(ref) : Mat4::Identity; }
void Collision::SetLocalTransform(Mat4 m) {
if (scene_ref && scene_ref->scene)
scene_ref->scene->SetCollisionLocalTransform(ref, m);
}
float Collision::GetMass() const { return scene_ref && scene_ref->scene ? scene_ref->scene->GetCollisionMass(ref) : 0.f; }
void Collision::SetMass(float mass) {

View File

@ -198,7 +198,8 @@ void ImGuiCreateFontTexture(DearImguiContext &ctx) {
ctx.m_texture = bgfx::createTexture2D((uint16_t)width, (uint16_t)height, false, 1, bgfx::TextureFormat::BGRA8, 0, bgfx::copy(data, width * height * 4));
io.Fonts->ClearInputData();
// commented out because we don't want to destroy imgui mouse cursors
// io.Fonts->ClearInputData();
io.Fonts->ClearTexData();
}

View File

@ -95,3 +95,8 @@ void AddImageRounded(ImDrawList *draw_list, const hg::Texture &tex, const ImVec2
float rounding, int rounding_corners = ImDrawCornerFlags_All);
} // namespace ImGui
inline ImVec2 operator+(const ImVec2 &a, const ImVec2 &b) { return {a.x + b.x, a.y + b.y}; }
inline ImVec2 operator-(const ImVec2 &a, const ImVec2 &b) { return {a.x - b.x, a.y - b.y}; }
inline ImVec2 operator*(const ImVec2 &a, const ImVec2 &b) { return {a.x * b.x, a.y * b.y}; }
inline ImVec2 operator/(const ImVec2 &a, const ImVec2 &b) { return {a.x / b.x, a.y / b.y}; }

View File

@ -10,6 +10,12 @@
namespace hg {
bool IsValid(const Downsample &downsample) {
return bgfx::isValid(downsample.compute) && bgfx::isValid(downsample.u_color) && bgfx::isValid(downsample.u_attr0) && bgfx::isValid(downsample.u_depth) &&
bgfx::isValid(downsample.fb) && bgfx::isValid(downsample.color.handle) && bgfx::isValid(downsample.attr0.handle) &&
bgfx::isValid(downsample.depth.handle);
}
static Downsample _CreateDownsample(const Reader &ir, const ReadProvider &ip, const char *path) {
Downsample down;
down.compute = hg::LoadProgram(ir, ip, hg::format("%1/shader/aaa_downsample").arg(path));
@ -21,16 +27,22 @@ static Downsample _CreateDownsample(const Reader &ir, const ReadProvider &ip, co
0 | BGFX_TEXTURE_RT | BGFX_SAMPLER_MIN_POINT | BGFX_SAMPLER_MAG_POINT | BGFX_SAMPLER_MIP_POINT | BGFX_SAMPLER_U_CLAMP | BGFX_SAMPLER_V_CLAMP;
down.color = {flags, bgfx::createTexture2D(bgfx::BackbufferRatio::Half, false, 1, bgfx::TextureFormat::RGBA32F, flags)};
bgfx::setName(down.color.handle, "color.downsampled");
down.attr0 = {flags, bgfx::createTexture2D(bgfx::BackbufferRatio::Half, false, 1, bgfx::TextureFormat::RGBA16F, flags)};
bgfx::setName(down.attr0.handle, "attr0.downsampled");
down.depth = {flags, bgfx::createTexture2D(bgfx::BackbufferRatio::Half, false, 1, bgfx::TextureFormat::R32F, flags)};
bgfx::setName(down.depth.handle, "depth.downsampled");
bgfx::TextureHandle texs[] = {down.color.handle, down.attr0.handle, down.depth.handle};
down.fb = bgfx::createFrameBuffer(3, texs, true);
if (!IsValid(down)) {
DestroyDownsample(down);
return down;
}
bgfx::setName(down.depth.handle, "depth.downsampled");
bgfx::setName(down.color.handle, "color.downsampled");
bgfx::setName(down.attr0.handle, "attr0.downsampled");
bgfx::setName(down.fb, "Downsample FB");
return down;
@ -45,18 +57,15 @@ void DestroyDownsample(Downsample &down) {
bgfx_Destroy(down.u_attr0);
bgfx_Destroy(down.u_depth);
bgfx_Destroy(down.fb);
down.compute = BGFX_INVALID_HANDLE;
down.u_color = BGFX_INVALID_HANDLE;
down.u_attr0 = BGFX_INVALID_HANDLE;
down.fb = BGFX_INVALID_HANDLE;
down.depth = BGFX_INVALID_HANDLE;
down.color = BGFX_INVALID_HANDLE;
down.attr0 = BGFX_INVALID_HANDLE;
down.depth = BGFX_INVALID_HANDLE;
}
// [todo] use a pyramid
void ComputeDownsample(bgfx::ViewId &view_id, const iRect &rect, const Texture &color, const Texture &attr0, const Texture &depth, const Downsample &down) {
__ASSERT__(IsValid(down));
const bgfx::Caps *caps = bgfx::getCaps();
bgfx::TransientIndexBuffer idx;

View File

@ -25,4 +25,6 @@ void DestroyDownsample(Downsample &downsample);
void ComputeDownsample(
bgfx::ViewId &view_id, const iRect &rect, const Texture &color, const Texture &attr0, const Texture &depth, const Downsample &downsample);
bool IsValid(const Downsample &downsample);
} // namespace hg

View File

@ -10,6 +10,11 @@
namespace hg {
bool IsValid(const HiZ &hiz) {
return bgfx::isValid(hiz.pyramid.handle) && bgfx::isValid(hiz.prg_copy) && bgfx::isValid(hiz.prg_compute) && bgfx::isValid(hiz.u_depth) &&
bgfx::isValid(hiz.u_projection);
}
static HiZ _CreateHiZ(const Reader &ir, const ReadProvider &ip, const char *path, bgfx::BackbufferRatio::Enum ratio) {
HiZ hiz;
@ -44,12 +49,17 @@ static HiZ _CreateHiZ(const Reader &ir, const ReadProvider &ip, const char *path
bgfx::TextureHandle handle = bgfx::createTexture2D(hiz.pyramid_infos.width, hiz.pyramid_infos.height, hiz.pyramid_infos.numMips,
hiz.pyramid_infos.numLayers, hiz.pyramid_infos.format, BGFX_TEXTURE_COMPUTE_WRITE | flags);
bgfx::setName(handle, "hiz.pyramid");
hiz.pyramid = hg::MakeTexture(handle, BGFX_TEXTURE_COMPUTE_WRITE | flags);
hiz.pyramid = hg::MakeTexture(handle, BGFX_TEXTURE_COMPUTE_WRITE | flags);
hiz.prg_copy = hg::LoadComputeProgram(ir, ip, hg::format("%1/shader/hiz_copy_cs.sc").arg(path));
hiz.prg_compute = hg::LoadComputeProgram(ir, ip, hg::format("%1/shader/hiz_compute_cs.sc").arg(path));
if (!IsValid(hiz)) {
DestroyHiZ(hiz);
return hiz;
}
bgfx::setName(handle, "hiz.pyramid");
return hiz;
}
@ -65,6 +75,8 @@ void DestroyHiZ(HiZ &hiz) {
}
void ComputeHiZ(bgfx::ViewId &view_id, const iRect &rect, const Mat44& proj, const Texture &depth, const HiZ &hiz) {
__ASSERT__(IsValid(hiz));
bgfx::setUniform(hiz.u_projection, to_bgfx(proj).data());
bgfx::setViewName(view_id, "HiZ copy");

View File

@ -16,7 +16,6 @@ struct HiZ {
bgfx::ProgramHandle prg_compute = BGFX_INVALID_HANDLE;
bgfx::UniformHandle u_depth = BGFX_INVALID_HANDLE;
bgfx::UniformHandle u_projection = BGFX_INVALID_HANDLE;
bgfx::UniformHandle u_resolution = BGFX_INVALID_HANDLE;
};
HiZ CreateHiZFromFile(const char *path, bgfx::BackbufferRatio::Enum ratio);
@ -27,4 +26,6 @@ void DestroyHiZ(HiZ &hiz);
/// @note input depth buffer must be in linear depth
void ComputeHiZ(bgfx::ViewId &view_id, const iRect &rect, const Mat44 &proj, const Texture &attr0, const HiZ &hiz);
bool IsValid(const HiZ &hiz);
} // namespace hg

View File

@ -384,7 +384,7 @@ IsoSurface ConvoluteIsoSurface(const IsoSurface &surface, int width, int height,
}
IsoSurface GaussianBlurIsoSurface(const IsoSurface &surface, int width, int height, int depth) {
static float kernel[27] = {
static const float kernel[27] = {
0.3f * 0.6f, 0.6f * 0.6f, 0.3f * 0.6f,
0.6f * 0.6f, 1.f * 0.6f, 0.6f * 0.6f,
0.3f * 0.6f, 0.6f * 0.6f, 0.3f * 0.6f,

View File

@ -84,8 +84,8 @@ json LoadJson(const Reader &ir, const Handle &h, bool *result) {
return js;
}
json LoadJsonFromFile(const char *path, bool *result) { return LoadJson(g_file_reader, ScopedReadHandle(g_file_read_provider, path), result); }
json LoadJsonFromAssets(const char *name, bool *result) { return LoadJson(g_assets_reader, ScopedReadHandle(g_assets_read_provider, name), result); }
json LoadJsonFromFile(const char *path, bool *result) { return LoadJson(g_file_reader, ScopedReadHandle(g_file_read_provider, path, true), result); }
json LoadJsonFromAssets(const char *name, bool *result) { return LoadJson(g_assets_reader, ScopedReadHandle(g_assets_read_provider, name, true), result); }
bool SaveJsonToFile(const json &js, const char *path) {
const auto js_ = js.dump(1, '\t', true);

View File

@ -10,6 +10,11 @@
namespace hg {
bool IsValid(const MotionBlur &motion_blur) {
return bgfx::isValid(motion_blur.prg_motion_blur) && bgfx::isValid(motion_blur.u_color) && bgfx::isValid(motion_blur.u_attr0) &&
bgfx::isValid(motion_blur.u_attr1) && bgfx::isValid(motion_blur.u_noise);
}
static MotionBlur _CreateMotionBlur(const Reader &ir, const ReadProvider &ip, const char *path) {
MotionBlur motion_blur;
@ -19,6 +24,9 @@ static MotionBlur _CreateMotionBlur(const Reader &ir, const ReadProvider &ip, co
motion_blur.u_attr1 = bgfx::createUniform("u_attr1", bgfx::UniformType::Sampler);
motion_blur.u_noise = bgfx::createUniform("u_noise", bgfx::UniformType::Sampler);
if (!IsValid(motion_blur)) {
DestroyMotionBlur(motion_blur);
}
return motion_blur;
}
@ -35,6 +43,8 @@ void DestroyMotionBlur(MotionBlur &motion_blur) {
void ApplyMotionBlur(bgfx::ViewId &view_id, const iRect &rect, const Texture &color, const Texture &attr0, const Texture &attr1, const Texture &noise,
bgfx::FrameBufferHandle output, const MotionBlur &motion_blur) {
__ASSERT__(IsValid(motion_blur));
const bgfx::Caps *caps = bgfx::getCaps();
bgfx::TransientIndexBuffer idx;

View File

@ -24,4 +24,6 @@ void DestroyMotionBlur(MotionBlur &motion_blur);
void ApplyMotionBlur(bgfx::ViewId &view_id, const iRect &rect, const Texture &color, const Texture &attr0, const Texture &attr1, const Texture &noise,
bgfx::FrameBufferHandle output, const MotionBlur &motion_blur);
bool IsValid(const MotionBlur &motion_blur);
} // namespace hg

View File

@ -167,7 +167,7 @@ struct Light { // 16B on 64 bit
};
//
enum RigidBodyType : uint8_t { RBT_Dynamic, RBT_Kinematic, RBT_Static};
enum RigidBodyType : uint8_t { RBT_Dynamic, RBT_Kinematic, RBT_Static };
struct RigidBody { // 16B on 64 bit
bool IsValid() const;
@ -187,6 +187,8 @@ struct RigidBody { // 16B on 64 bit
void SetRestitution(float restitution);
float GetFriction() const;
void SetFriction(float friction);
float GetRollingFriction() const;
void SetRollingFriction(float rolling_friction);
intrusive_shared_ptr_st<SceneRef> scene_ref;
ComponentRef ref;
@ -204,6 +206,8 @@ struct Collision { // 16B on 64 bit
CollisionType GetType() const;
void SetType(CollisionType type);
Mat4 GetLocalTransform() const;
void SetLocalTransform(Mat4 m);
float GetMass() const;
void SetMass(float mass);
float GetRadius() const;

View File

@ -36,14 +36,14 @@ static std::array<OpenVRTrackedDeviceState, vr::k_unMaxTrackedDeviceCount> openv
static uint32_t rt_width = 0, rt_height = 0;
static Mat44 OVRToMat44(const vr::HmdMatrix44_t &m) {
static Mat44 VR_to_gs(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 1);
static const Mat44 VR_to_gs(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 1);
return /*VR_to_gs * */ Mat44(m.m[0][0], m.m[1][0], m.m[2][0], m.m[3][0], m.m[0][1], m.m[1][1], m.m[2][1], m.m[3][1], m.m[0][2], m.m[1][2], m.m[2][2],
m.m[3][2], m.m[0][3], m.m[1][3], m.m[2][3], m.m[3][3]) *
VR_to_gs;
}
static Mat4 OVRToMat4(const vr::HmdMatrix34_t &m) {
static Mat4 VR_to_gs(1, 0, 0, 0, 1, 0, 0, 0, -1, 0, 0, 0);
static const Mat4 VR_to_gs(1, 0, 0, 0, 1, 0, 0, 0, -1, 0, 0, 0);
return VR_to_gs * Mat4(m.m[0][0], m.m[1][0], m.m[2][0], m.m[0][1], m.m[1][1], m.m[2][1], m.m[0][2], m.m[1][2], m.m[2][2], m.m[0][3], m.m[1][3], m.m[2][3]) *
VR_to_gs;
}

View File

@ -13,12 +13,12 @@
namespace hg {
int size_of(PictureFormat format) {
static int size_of_format[PF_Last] = {0, 3, 4, 16};
static const int size_of_format[PF_Last] = {0, 3, 4, 16};
return size_of_format[format];
}
size_t GetChannelCount(PictureFormat format) {
static size_t channel_count_format[PF_Last] = {0, 3, 4, 4};
static const size_t channel_count_format[PF_Last] = {0, 3, 4, 4};
return channel_count_format[format];
}

View File

@ -177,21 +177,21 @@ void DrawNavMesh(const dtNavMesh *mesh, bgfx::ViewId view_id, const bgfx::Vertex
int tileNum = mesh->decodePolyIdTile(base);
for (int i = 0; i < tile->header->polyCount; ++i) {
const dtPoly *p = &tile->polys[i];
for (int j = 0; j < tile->header->polyCount; ++j) {
const dtPoly *p = &tile->polys[j];
if (p->getType() == DT_POLYTYPE_OFFMESH_CONNECTION) // Skip off-mesh links.
continue;
const dtPolyDetail *pd = &tile->detailMeshes[i];
const dtPolyDetail *pd = &tile->detailMeshes[j];
for (int j = 0; j < pd->triCount; ++j) {
const unsigned char *t = &tile->detailTris[(pd->triBase + j) * 4];
for (int k = 0; k < 3; ++k) {
if (t[k] < p->vertCount) {
float *v = &tile->verts[p->verts[t[k]] * 3];
for (int k = 0; k < pd->triCount; ++k) {
const unsigned char *t = &tile->detailTris[(pd->triBase + k) * 4];
for (int l = 0; l < 3; ++l) {
if (t[l] < p->vertCount) {
float *v = &tile->verts[p->verts[t[l]] * 3];
vtx.Begin(vtx_count++).SetPos(Vec3(v[0], v[1], v[2])).SetColor0(col).End();
} else {
float *v = &tile->detailVerts[(pd->vertBase + t[k] - p->vertCount) * 3];
float *v = &tile->detailVerts[(pd->vertBase + t[l] - p->vertCount) * 3];
vtx.Begin(vtx_count++).SetPos(Vec3(v[0], v[1], v[2])).SetColor0(col).End();
}
}

View File

@ -694,7 +694,7 @@ std::vector<PipelineProgramFeature> LoadPipelineProgramFeaturesFromAssets(const
//
bool LoadPipelineProgramUniforms(const Reader &ir, const ReadProvider &ip, const char *name, std::vector<TextureUniform> &texs, std::vector<Vec4Uniform> &vecs,
PipelineResources &resources) {
const auto json_text = LoadString(ir, ScopedReadHandle(ip, name));
const auto json_text = LoadString(ir, ScopedReadHandle(ip, name, true));
if (json_text.empty())
return false;
@ -702,7 +702,7 @@ bool LoadPipelineProgramUniforms(const Reader &ir, const ReadProvider &ip, const
const auto i = js.find("uniforms");
if (i == std::end(js))
return false;
return true; // [EJ] if there's no uniforms declared look no further
for (const auto &j : *i) {
const auto uname = j["name"].get<std::string>();
@ -2223,7 +2223,8 @@ void Vertices::End(bool validate) {
"Weight", "TexCoord0", "TexCoord1", "TexCoord2", "TexCoord3", "TexCoord4", "TexCoord5", "TexCoord6", "TexCoord7"};
for (int attr = 0; attr < bgfx::Attrib::Count; ++attr)
if (decl.has(bgfx::Attrib::Enum(attr)) && !(vtx_attr_flag & (1 << attr))) // attribute expected by the vertex layout but missing from vertex declaration
if (decl.has(bgfx::Attrib::Enum(attr)) &&
!(vtx_attr_flag & (1 << attr))) // attribute expected by the vertex layout but missing from vertex declaration
warn(format("Incomplete vertex #%1 declaration: missing %2 attribute").arg(idx).arg(attr_name[attr]));
}
@ -2490,8 +2491,8 @@ void SetView2D(bgfx::ViewId id, int x, int y, int res_x, int res_y, float znear,
bgfx::setViewTransform(id, _view.data(), _proj.data());
}
void SetViewPerspective(bgfx::ViewId id, int x, int y, int res_x, int res_y, const Mat4 &world, float znear, float zfar, float zoom_factor, uint16_t clear_flags,
const Color &clear_color, float depth, uint8_t stencil, const Vec2 &aspect_ratio) {
void SetViewPerspective(bgfx::ViewId id, int x, int y, int res_x, int res_y, const Mat4 &world, float znear, float zfar, float zoom_factor,
uint16_t clear_flags, const Color &clear_color, float depth, uint8_t stencil, const Vec2 &aspect_ratio) {
const bgfx::Caps *caps = bgfx::getCaps();
bgfx::setViewClear(id, clear_flags, ColorToABGR32(clear_color), depth, stencil);
@ -2521,6 +2522,24 @@ void SetViewOrthographic(bgfx::ViewId id, int x, int y, int res_x, int res_y, co
}
//
static inline FrameBuffer CreateFrameBuffer(bgfx::TextureHandle color, bgfx::TextureHandle depth, const char *name, bool own_textures) {
bgfx::TextureHandle texs[] = {color, depth};
if (own_textures) {
bgfx::setName(color, format("FrameBuffer.color (%1)").arg(name).c_str());
bgfx::setName(depth, format("FrameBuffer.depth (%1)").arg(name).c_str());
}
bgfx::FrameBufferHandle handle = bgfx::createFrameBuffer(2, texs, own_textures);
bgfx::setName(handle, format("FrameBuffer (%1)").arg(name).c_str());
return {handle};
}
FrameBuffer CreateFrameBuffer(const hg::Texture &color, const hg::Texture &depth, const char *name) {
return CreateFrameBuffer(color.handle, depth.handle, name, false);
}
static inline uint64_t ComputeTextureRTMSAAFlag(int aa) {
switch (aa) {
case 2:
@ -2536,60 +2555,31 @@ static inline uint64_t ComputeTextureRTMSAAFlag(int aa) {
}
}
static inline PipelineFrameBuffer CreateFrameBuffer(hg::Texture &color, hg::Texture &depth, PipelineResources &res, const char *name) {
auto color_name = format("FrameBuffer.color (%1)").arg(name);
auto depth_name = format("FrameBuffer.depth (%1)").arg(name);
bgfx::setName(color.handle, color_name.c_str());
bgfx::setName(depth.handle, depth_name.c_str());
PipelineFrameBuffer frame_buffer;
bgfx::TextureHandle texs[] = {color.handle, depth.handle};
frame_buffer.handle = bgfx::createFrameBuffer(2, texs);
bgfx::setName(frame_buffer.handle, format("FrameBuffer (%1)").arg(name).c_str());
res.textures.Destroy(res.textures.Has(color_name.c_str()));
frame_buffer.color = res.textures.Add(color_name.c_str(), color);
res.textures.Destroy(res.textures.Has(depth_name.c_str()));
frame_buffer.depth = res.textures.Add(depth_name.c_str(), depth);
return frame_buffer;
}
PipelineFrameBuffer CreateFrameBuffer(
bgfx::TextureFormat::Enum color_format, bgfx::TextureFormat::Enum depth_format, int aa, PipelineResources &res, const char *name) {
FrameBuffer CreateFrameBuffer(bgfx::TextureFormat::Enum color_format, bgfx::TextureFormat::Enum depth_format, int aa, const char *name) {
uint64_t flags = ComputeTextureRTMSAAFlag(aa);
hg::Texture color, depth;
color.flags = flags;
color.handle = bgfx::createTexture2D(bgfx::BackbufferRatio::Equal, false, 1, color_format, color.flags);
const auto color = bgfx::createTexture2D(bgfx::BackbufferRatio::Equal, false, 1, color_format, flags);
const auto depth = bgfx::createTexture2D(bgfx::BackbufferRatio::Equal, false, 1, depth_format, flags | BGFX_TEXTURE_RT_WRITE_ONLY);
depth.flags = BGFX_TEXTURE_RT_WRITE_ONLY | flags;
depth.handle = bgfx::createTexture2D(bgfx::BackbufferRatio::Equal, false, 1, depth_format, depth.flags);
return CreateFrameBuffer(color, depth, res, name);
return CreateFrameBuffer(color, depth, name, true);
}
PipelineFrameBuffer CreateFrameBuffer(
int width, int height, bgfx::TextureFormat::Enum color_format, bgfx::TextureFormat::Enum depth_format, int aa, PipelineResources &res, const char *name) {
FrameBuffer CreateFrameBuffer(int width, int height, bgfx::TextureFormat::Enum color_format, bgfx::TextureFormat::Enum depth_format, int aa, const char *name) {
uint64_t flags = ComputeTextureRTMSAAFlag(aa);
hg::Texture color, depth;
color.flags = flags;
color.handle = bgfx::createTexture2D(width, height, false, 1, color_format, color.flags);
const auto color = bgfx::createTexture2D(width, height, false, 1, color_format, flags);
const auto depth = bgfx::createTexture2D(width, height, false, 1, depth_format, flags | BGFX_TEXTURE_RT_WRITE_ONLY);
depth.flags = BGFX_TEXTURE_RT_WRITE_ONLY | flags;
depth.handle = bgfx::createTexture2D(width, height, false, 1, depth_format, depth.flags);
return CreateFrameBuffer(color, depth, res, name);
return CreateFrameBuffer(color, depth, name, true);
}
void DestroyFrameBuffer(PipelineResources &res, PipelineFrameBuffer &frameBuffer) {
res.textures.Destroy(frameBuffer.color);
res.textures.Destroy(frameBuffer.depth);
bgfx::destroy(frameBuffer.handle);
}
Texture GetColorTexture(FrameBuffer &frameBuffer) { return MakeTexture(bgfx::getTexture(frameBuffer.handle, 0)); }
Texture GetDepthTexture(FrameBuffer &frameBuffer) { return MakeTexture(bgfx::getTexture(frameBuffer.handle, 1)); }
void DestroyFrameBuffer(FrameBuffer &frameBuffer) { bgfx::destroy(frameBuffer.handle); }
//
bool CreateFullscreenQuad(bgfx::TransientIndexBuffer &idx, bgfx::TransientVertexBuffer &vtx) {
bgfx::VertexLayout layout;
layout.begin().add(bgfx::Attrib::Position, 3, bgfx::AttribType::Float).add(bgfx::Attrib::TexCoord0, 2, bgfx::AttribType::Float).end();

View File

@ -84,12 +84,12 @@ bool IsRenderUp();
/// Fit the backbuffer to the specified window client area dimensions, return true if resizing was carried out.
bool RenderResetToWindow(Window *win, int &width, int &height, uint32_t reset_flags = 0);
void SetView2D(bgfx::ViewId id, int x, int y, int res_x, int res_y, float znear = -1.f, float zfar = 1.f, uint16_t clear_flags = BGFX_CLEAR_COLOR | BGFX_CLEAR_DEPTH,
const Color &clear_color = Color::Black, float depth = 1.f, uint8_t stencil = 0, bool y_up = false);
void SetViewPerspective(bgfx::ViewId id, int x, int y, int res_x, int res_y, const Mat4 &world, float znear = 0.01f, float zfar = 1000.f,
float zoom_factor = 1.8,
void SetView2D(bgfx::ViewId id, int x, int y, int res_x, int res_y, float znear = -1.f, float zfar = 1.f,
uint16_t clear_flags = BGFX_CLEAR_COLOR | BGFX_CLEAR_DEPTH, const Color &clear_color = Color::Black, float depth = 1.f, uint8_t stencil = 0,
const Vec2 &aspect_ratio = {});
bool y_up = false);
void SetViewPerspective(bgfx::ViewId id, int x, int y, int res_x, int res_y, const Mat4 &world, float znear = 0.01f, float zfar = 1000.f,
float zoom_factor = 1.8, uint16_t clear_flags = BGFX_CLEAR_COLOR | BGFX_CLEAR_DEPTH, const Color &clear_color = Color::Black, float depth = 1.f,
uint8_t stencil = 0, const Vec2 &aspect_ratio = {});
void SetViewOrthographic(bgfx::ViewId id, int x, int y, int res_x, int res_y, const Mat4 &world, float znear = 0.01f, float zfar = 1000.f, float size = 1.f,
uint16_t clear_flags = BGFX_CLEAR_COLOR | BGFX_CLEAR_DEPTH, const Color &clear_color = Color::Black, float depth = 1.f, uint8_t stencil = 0,
const Vec2 &aspect_ratio = {});
@ -618,18 +618,18 @@ struct Pipeline {
void DestroyPipeline(Pipeline &pipeline);
//
struct PipelineFrameBuffer {
struct FrameBuffer {
bgfx::FrameBufferHandle handle = BGFX_INVALID_HANDLE;
TextureRef color, depth;
};
PipelineFrameBuffer CreateFrameBuffer(
bgfx::TextureFormat::Enum color_format, bgfx::TextureFormat::Enum depth_format, int aa, PipelineResources &res, const char *name);
FrameBuffer CreateFrameBuffer(const hg::Texture &color, const hg::Texture &depth, const char *name);
FrameBuffer CreateFrameBuffer(bgfx::TextureFormat::Enum color_format, bgfx::TextureFormat::Enum depth_format, int aa, const char *name);
FrameBuffer CreateFrameBuffer(int width, int height, bgfx::TextureFormat::Enum color_format, bgfx::TextureFormat::Enum depth_format, int aa, const char *name);
PipelineFrameBuffer CreateFrameBuffer(
int width, int height, bgfx::TextureFormat::Enum color_format, bgfx::TextureFormat::Enum depth_format, int aa, PipelineResources &res, const char *name);
Texture GetColorTexture(FrameBuffer &frameBuffer);
Texture GetDepthTexture(FrameBuffer &frameBuffer);
void DestroyFrameBuffer(PipelineResources &res, PipelineFrameBuffer &frameBuffer);
void DestroyFrameBuffer(FrameBuffer &frameBuffer);
bool CreateFullscreenQuad(bgfx::TransientIndexBuffer &idx, bgfx::TransientVertexBuffer &vtx);

Some files were not shown because too many files have changed in this diff Show More