diff --git a/.gitignore b/.gitignore index a3b1086..36ec8b5 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,3 @@ /resources_compiled +/_bin +/assetc-ubuntu-x64-2.3.0 diff --git a/.vscode/launch.json b/.vscode/launch.json index 8aae0ce..5f60e88 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -3,7 +3,7 @@ // Hover to view descriptions of existing attributes. // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 "version": "0.2.0", - "configurations": [ + "configurations": [ { "name": "Python: Current File", "type": "python", @@ -19,7 +19,14 @@ "stopOnEntry": false, "program": "${file}", "cwd": "${workspaceFolder}/", - "luaexe": "${workspaceFolder}/_bin/lua.exe", + "luaexe": "d:/harfang/hg_lua/lua.exe", + }, + { + "name": "Go: Current file", + "type": "go", + "request": "launch", + "mode": "debug", + "program": "${file}" } ] } diff --git a/README.md b/README.md index b087596..31d57f8 100644 --- a/README.md +++ b/README.md @@ -17,6 +17,10 @@ You can now execute the tutorials from the folder you unzipped them to. ```bash D:\tutorials-hg2>python draw_lines.py ``` +or +```bash +D:\tutorials-hg2>go run draw_lines.go +``` Alternatively, you can open the tutorial folder using [Visual Studio Code](https://code.visualstudio.com/) and use the provided debug targets to run the tutorials. diff --git a/audio_play_sound_spatialized.go b/audio_play_sound_spatialized.go new file mode 100644 index 0000000..9fff854 --- /dev/null +++ b/audio_play_sound_spatialized.go @@ -0,0 +1,37 @@ +package main + +import ( + "math" + + hg "github.com/harfang3d/harfang-go/v3" +) + +func main() { + hg.InputInit() + hg.AudioInit() + + hg.AddAssetsFolder("resources_compiled") + + snd_ref := hg.LoadWAVSoundAsset("sounds/metro_announce.wav") + src_ref := hg.PlaySpatialized(hg.SoundRef(snd_ref), hg.NewSpatializedSourceStateWithMtxVolumeRepeat(hg.Mat4GetIdentity(), 1, hg.SRLoop)) + + angle := 0.0 + + for !hg.ReadKeyboard().Key(hg.KEscape) { + dt := hg.TickClock() + dt_sec_f := hg.TimeToSecF(dt) // delta frame in seconds + + // compute the source old and new position in world + src_old_pos := hg.NewVec3WithXYZ(float32(math.Sin(angle)), 0, float32(math.Cos(angle))).MulWithK(5.0) + angle += float64(hg.TimeToSecF(hg.TickClock())) * 45.0 + src_new_pos := hg.NewVec3WithXYZ(float32(math.Sin(angle)), 0, float32(math.Cos(angle))).MulWithK(5.0) + + // source velocity in m.s-1 + src_vel := (src_new_pos.Sub(src_old_pos)).DivWithK(dt_sec_f) + + // update source properties + hg.SetSourceTransform(hg.SourceRef(src_ref), hg.TranslationMat4(src_new_pos), src_vel) + } + hg.AudioShutdown() + hg.InputShutdown() +} diff --git a/audio_play_sound_stereo.go b/audio_play_sound_stereo.go new file mode 100644 index 0000000..6bceb32 --- /dev/null +++ b/audio_play_sound_stereo.go @@ -0,0 +1,24 @@ +package main + +import ( + "math" + + hg "github.com/harfang3d/harfang-go/v3" +) + +func main() { + hg.InputInit() + hg.AudioInit() + + snd_ref := hg.LoadWAVSoundFile("resources_compiled/sounds/metro_announce.wav") // WAV 44.1kHz 16bit mono + src_ref := hg.PlayStereo(hg.SoundRef(snd_ref), hg.NewStereoSourceStateWithVolumeRepeat(1, hg.SRLoop)) + + angle := 0.0 + + for !hg.ReadKeyboardWithName("raw").Key(hg.KEscape) { + angle += float64(hg.TimeToSecF(hg.TickClock())) * 0.5 + hg.SetSourcePanning(hg.SourceRef(src_ref), float32(math.Sin(angle))) // panning left = -1, panning right = 1 + } + hg.AudioShutdown() + hg.InputShutdown() +} diff --git a/audio_stream_ogg_stereo.go b/audio_stream_ogg_stereo.go new file mode 100644 index 0000000..4b969a1 --- /dev/null +++ b/audio_stream_ogg_stereo.go @@ -0,0 +1,23 @@ +package main + +import ( + "math" + + hg "github.com/harfang3d/harfang-go/v3" +) + +func main() { + hg.InputInit() + hg.AudioInit() + + src_ref := hg.StreamOGGFileStereo("resources_compiled/sounds/metro_announce.ogg", hg.NewStereoSourceStateWithVolumeRepeat(1, hg.SRLoop)) // OGG 44.1kHz 16bit mono + + angle := 0.0 + + for !hg.ReadKeyboardWithName("raw").Key(hg.KEscape) { + angle += float64(hg.TimeToSecF(hg.TickClock())) * 0.5 + hg.SetSourcePanning(hg.SourceRef(src_ref), float32(math.Sin(angle))) // panning left = -1, panning right = 1 + } + hg.AudioShutdown() + hg.InputShutdown() +} diff --git a/basic_loop.go b/basic_loop.go new file mode 100644 index 0000000..a7aa3b7 --- /dev/null +++ b/basic_loop.go @@ -0,0 +1,31 @@ +package main + +import ( + "runtime" + + hg "github.com/harfang3d/harfang-go/v3" +) + +func main() { + hg.InputInit() + hg.WindowSystemInit() + + width, height := int32(1280), int32(720) + + window := hg.RenderInitWithWindowTitleWidthHeightResetFlags("Harfang - Basic Loop", width, height, hg.RFVSync) + + for !hg.ReadKeyboard().Key(hg.KEscape) && hg.IsWindowOpen(window) { + hg.SetViewClearWithColDepthStencil(0, hg.CFColor|hg.CFDepth, hg.ColorGetGreen(), 1, 0) + hg.SetViewRect(0, 0, 0, uint16(width), uint16(height)) + + hg.Touch(0) // force the view to be processed as it would be ignored since nothing is drawn to it (a clear does not count) + + hg.Frame() + hg.UpdateWindow(window) + runtime.GC() + } + + hg.RenderShutdown() + hg.DestroyWindow(window) + +} diff --git a/draw_lines.go b/draw_lines.go new file mode 100644 index 0000000..c978364 --- /dev/null +++ b/draw_lines.go @@ -0,0 +1,55 @@ +package main + +import ( + "math" + "runtime" + + hg "github.com/harfang3d/harfang-go/v3" +) + +func main() { + hg.InputInit() + hg.WindowSystemInit() + + resX, resY := int32(1280), int32(720) + + window := hg.RenderInitWithWindowTitleWidthHeightResetFlags("Harfang - Draw Lines", resX, resY, hg.RFVSync|hg.RFMSAA4X) + + lineCount := int32(1000) + + shader := hg.LoadProgramFromFile("resources_compiled/shaders/white") + + // vertices + vtxLayout := hg.NewVertexLayout() + vtxLayout.Begin() + vtxLayout.Add(hg.APosition, 3, hg.ATFloat) + vtxLayout.End() + + vtx := hg.NewVertices(vtxLayout, lineCount*2) + + // main loop + angle := 0.0 + + for !hg.ReadKeyboard().Key(hg.KEscape) && hg.IsWindowOpen(window) { + hg.SetViewClearWithColDepthStencil(0, hg.CFColor|hg.CFDepth, hg.ColorI(64, 64, 64), 1.0, 0) + hg.SetViewRect(0, 0, 0, uint16(resX), uint16(resY)) + + vtx.Clear() + for i := 0.0; i < float64(lineCount); i++ { + vtx.Begin(int32(2 * i)).SetPos(hg.NewVec3WithXYZ(float32(math.Sin(angle+i*0.005)), float32(math.Cos(angle+i*0.01)), 0.0)).End() + vtx.Begin(int32(2*i + 1)).SetPos(hg.NewVec3WithXYZ(float32(math.Sin(angle+i*-0.005)), float32(math.Cos(angle+i*0.005)), 0.0)).End() + } + + hg.DrawLines(0, vtx, shader) // submit all lines in a single call + + angle = angle + float64(hg.TimeToSecF(hg.TickClock())) + + hg.Frame() + hg.UpdateWindow(window) + runtime.GC() + } + + hg.RenderShutdown() + hg.DestroyWindow(window) + +} diff --git a/draw_lines_starfield.go b/draw_lines_starfield.go new file mode 100644 index 0000000..3ce12b0 --- /dev/null +++ b/draw_lines_starfield.go @@ -0,0 +1,67 @@ +package main + +import ( + "runtime" + + hg "github.com/harfang3d/harfang-go/v3" +) + +func main() { + hg.InputInit() + hg.WindowSystemInit() + + width, height := int32(1280), int32(720) + window := hg.RenderInitWithWindowTitleWidthHeightResetFlags("Harfang - Starfield", width, height, hg.RFVSync|hg.RFMSAA4X) + + // vertex layout + vtxLayout := hg.NewVertexLayout() + vtxLayout.Begin() + vtxLayout.Add(hg.APosition, 3, hg.ATFloat) + vtxLayout.Add(hg.AColor0, 3, hg.ATFloat) + vtxLayout.End() + + // simple shader program + shader := hg.LoadProgramFromFile("resources_compiled/shaders/pos_rgb") + + // initialize stars + starfieldSize := float32(10.0) + + maxStars := 1000 + vtx := hg.NewVertices(vtxLayout, int32(maxStars*2)) + + var stars []*hg.Vec3 + for i := 0; i < maxStars; i++ { + stars = append(stars, hg.RandomVec3(-starfieldSize, starfieldSize)) + } + + for !hg.ReadKeyboard().Key(hg.KEscape) && hg.IsWindowOpen(window) { + hg.SetViewClearWithColDepthStencil(0, hg.CFColor|hg.CFDepth, hg.ColorGetBlack(), 1.0, 0) + hg.SetViewRect(0, 0, 0, uint16(width), uint16(height)) + + dt := hg.TickClock() + dt_f := hg.TimeToSecF(dt) + + // update stars + vtx.Clear() + for i, star := range stars { + star.SetZ(star.GetZ() - float32(2.0*dt_f)) + if star.GetZ() < starfieldSize { + star.SetZ(star.GetZ() + starfieldSize) + } + + // draw stars + vtx.Begin(int32(2 * i)).SetPos(star.Mul(hg.NewVec3WithXYZ(1.0/star.GetZ(), 1.0/star.GetZ(), 0.0))).SetColor0(hg.ColorGetBlack()).End() + vtx.Begin(int32(2*i + 1)).SetPos(star.Mul(hg.NewVec3WithXYZ(1.04/star.GetZ(), 1.04/star.GetZ(), 0.0))).SetColor0(hg.ColorGetWhite()).End() + } + + hg.DrawLines(0, vtx, shader) + + hg.Frame() + hg.UpdateWindow(window) + runtime.GC() + } + + hg.RenderShutdown() + hg.DestroyWindow(window) + +} diff --git a/draw_model_no_pipeline.go b/draw_model_no_pipeline.go new file mode 100644 index 0000000..3040ad6 --- /dev/null +++ b/draw_model_no_pipeline.go @@ -0,0 +1,42 @@ +package main + +import ( + hg "github.com/harfang3d/harfang-go/v3" +) + +func main() { + hg.InputInit() + hg.WindowSystemInit() + + resX, resY := int32(1280), int32(720) + + window := hg.RenderInitWithWindowTitleWidthHeightResetFlags("Harfang - Draw Models no Pipeline", resX, resY, hg.RFVSync|hg.RFMSAA4X) + + // vertex layout and models + vtxLayout := hg.VertexLayoutPosFloatNormUInt8() + + cubeMdl := hg.CreateCubeModel(vtxLayout, 1, 1, 1) + groundMdl := hg.CreatePlaneModel(vtxLayout, 5, 5, 1, 1) + + shader := hg.LoadProgramFromFile("resources_compiled/shaders/mdl") + + // main loop + angle := float32(0.0) + + for !hg.ReadKeyboard().Key(hg.KEscape) && hg.IsWindowOpen(window) { + dt := hg.TickClock() + angle = angle + hg.TimeToSecF(dt) + + viewpoint := hg.TranslationMat4(hg.NewVec3WithXYZ(0, 1, -3)) + hg.SetViewPerspective(0, 0, 0, resX, resY, viewpoint) + + hg.DrawModelWithSliceOfValuesSliceOfTextures(0, cubeMdl, shader, hg.GoSliceOfUniformSetValue{}, hg.GoSliceOfUniformSetTexture{}, hg.TransformationMat4(hg.NewVec3WithXYZ(0.0, 1, 0.0), hg.NewVec3WithXYZ(angle, angle, angle))) + hg.DrawModelWithSliceOfValuesSliceOfTextures(0, groundMdl, shader, hg.GoSliceOfUniformSetValue{}, hg.GoSliceOfUniformSetTexture{}, hg.TranslationMat4(hg.NewVec3WithXYZ(0.0, 0.0, 0.0))) + + hg.Frame() + hg.UpdateWindow(window) + } + + hg.RenderShutdown() + hg.DestroyWindow(window) +} diff --git a/draw_text.go b/draw_text.go new file mode 100644 index 0000000..c05f925 --- /dev/null +++ b/draw_text.go @@ -0,0 +1,34 @@ +package main + +import ( + hg "github.com/harfang3d/harfang-go/v3" +) + +func main() { + hg.InputInit() + hg.WindowSystemInit() + + resX, resY := int32(1280), int32(720) + win := hg.RenderInitWithWindowTitleWidthHeightResetFlags("Harfang - Draw Text", resX, resY, hg.RFVSync) + + // load font and shader program + font := hg.LoadFontFromFileWithSize("resources_compiled/font/default.ttf", 96) + font_prg := hg.LoadProgramFromFile("resources_compiled/core/shader/font") + + // text uniforms and render state + text_uniform_values := hg.GoSliceOfUniformSetValue{hg.MakeUniformSetValueWithVec4V("u_color", hg.NewVec4WithXYZ(1, 1, 0))} + text_render_state := hg.ComputeRenderStateWithDepthTestCulling(hg.BMAlpha, hg.DTAlways, hg.FCDisabled) + + // main loop + for !hg.ReadKeyboard().Key(hg.KEscape) && hg.IsWindowOpen(win) { + hg.SetView2DWithZnearZfarFlagsColorDepthStencil(0, 0, 0, resX, resY, -1, 1, hg.CFColor|hg.CFDepth, hg.ColorI(32, 32, 32), 0, 1) + + hg.DrawTextWithPosHalignValignSliceOfValuesSliceOfTexturesState(0, font, "Hello world!", font_prg, "u_tex", 0, hg.Mat4GetIdentity(), hg.NewVec3WithXYZ(float32(resX/2), float32(resY/2), 0), hg.DTHACenter, hg.DTVACenter, text_uniform_values, hg.GoSliceOfUniformSetTexture{}, text_render_state) + + hg.Frame() + hg.UpdateWindow(win) + } + + hg.RenderShutdown() + hg.DestroyWindow(win) +} diff --git a/draw_text_over_models.go b/draw_text_over_models.go new file mode 100644 index 0000000..1d41b26 --- /dev/null +++ b/draw_text_over_models.go @@ -0,0 +1,56 @@ +package main + +import ( + hg "github.com/harfang3d/harfang-go/v3" +) + +func main() { + hg.InputInit() + hg.WindowSystemInit() + + resX, resY := int32(1280), int32(720) + + window := hg.RenderInitWithWindowTitleWidthHeightResetFlags("Harfang - Draw Text over Models", resX, resY, hg.RFVSync|hg.RFMSAA4X) + + // vertex layout and models + vtxLayout := hg.VertexLayoutPosFloatNormUInt8() + + cubeMdl := hg.CreateCubeModel(vtxLayout, 1, 1, 1) + groundMdl := hg.CreatePlaneModel(vtxLayout, 5, 5, 1, 1) + + shader := hg.LoadProgramFromFile("resources_compiled/shaders/mdl") + + // load font and shader program + font := hg.LoadFontFromFileWithSize("resources_compiled/font/default.ttf", 96) + font_prg := hg.LoadProgramFromFile("resources_compiled/core/shader/font") + + // text uniforms and render state + text_uniform_values := hg.GoSliceOfUniformSetValue{hg.MakeUniformSetValueWithVec4V("u_color", hg.NewVec4WithXYZ(1, 1, 0))} + text_render_state := hg.ComputeRenderStateWithDepthTestCulling(hg.BMAlpha, hg.DTAlways, hg.FCDisabled) + + // main loop + angle := float32(0.0) + + for !hg.ReadKeyboard().Key(hg.KEscape) && hg.IsWindowOpen(window) { + dt := hg.TickClock() + angle = angle + hg.TimeToSecF(dt) + + // 3D view + viewpoint := hg.TranslationMat4(hg.NewVec3WithXYZ(0, 1, -3)) + hg.SetViewPerspectiveWithZnearZfar(0, 0, 0, resX, resY, viewpoint, 0.01, 5000) + + hg.DrawModelWithSliceOfValuesSliceOfTextures(0, cubeMdl, shader, hg.GoSliceOfUniformSetValue{}, hg.GoSliceOfUniformSetTexture{}, hg.TransformationMat4(hg.NewVec3WithXYZ(0, 1, 0), hg.NewVec3WithXYZ(angle, angle, angle))) + hg.DrawModelWithSliceOfValuesSliceOfTextures(0, groundMdl, shader, hg.GoSliceOfUniformSetValue{}, hg.GoSliceOfUniformSetTexture{}, hg.TranslationMat4(hg.NewVec3WithXYZ(0, 0, 0))) + + // 2D view, note that only the depth buffer is cleared + hg.SetView2DWithZnearZfarFlagsColorDepthStencil(1, 0, 0, resX, resY, -1, 1, hg.CFDepth, hg.ColorI(32, 32, 32), 1, 0) + + hg.DrawTextWithPosHalignValignSliceOfValuesSliceOfTexturesState(1, font, "Hello world!", font_prg, "u_tex", 0, hg.Mat4GetIdentity(), hg.NewVec3WithXYZ(float32(resX/2), float32(resY/2), 0), hg.DTHACenter, hg.DTVACenter, text_uniform_values, hg.GoSliceOfUniformSetTexture{}, text_render_state) + + hg.Frame() + hg.UpdateWindow(window) + } + + hg.RenderShutdown() + hg.DestroyWindow(window) +} diff --git a/filesystem_assets.go b/filesystem_assets.go new file mode 100644 index 0000000..316f86c --- /dev/null +++ b/filesystem_assets.go @@ -0,0 +1,28 @@ +package main + +import ( + "fmt" + + hg "github.com/harfang3d/harfang-go/v3" +) + +func main() { + hg.WindowSystemInit() + + resX, resY := int32(256), int32(256) + win := hg.RenderInitWithWindowTitleWidthHeightResetFlags("Harfang - Load from Assets", resX, resY, hg.RFVSync) + + // mount folder as an assets source and load texture from the assets system + hg.AddAssetsFolder("resources_compiled") + + tex, tex_info := hg.LoadTextureFromAssets("pictures/owl.jpg", 0) + + if hg.IsValidWithT(tex) { + fmt.Printf("Texture dimensions: %dx%d", tex_info.GetWidth(), tex_info.GetHeight()) + } else { + fmt.Printf("Failed to load texture") + } + + hg.RenderShutdown() + hg.DestroyWindow(win) +} diff --git a/filesystem_local.go b/filesystem_local.go new file mode 100644 index 0000000..cebc3ce --- /dev/null +++ b/filesystem_local.go @@ -0,0 +1,18 @@ +package main + +import ( + "fmt" + + hg "github.com/harfang3d/harfang-go/v3" +) + +func main() { + file := hg.Open("resources/pictures/owl.jpg") + + if hg.IsValid(file) { + fmt.Printf("File is %d bytes long", hg.GetSize(file)) + } else { + fmt.Printf("Failed to open file") + } + hg.Close(file) +} diff --git a/filesystem_recursive_directory_listing.go b/filesystem_recursive_directory_listing.go new file mode 100644 index 0000000..e28177a --- /dev/null +++ b/filesystem_recursive_directory_listing.go @@ -0,0 +1,20 @@ +package main + +import ( + "fmt" + + hg "github.com/harfang3d/harfang-go/v3" +) + +func EntryTypeToString(type_ int32) string { + return map[hg.DirEntryType]string{hg.DEFile: "file", hg.DEDir: "directory", hg.DELink: "link"}[hg.DirEntryType(type_)] +} + +func main() { + entries := hg.ListDirRecursive("resources", hg.DEAll) + + for i := int32(0); i < entries.Size(); i += 1 { + entry := entries.At(i) + fmt.Printf("- %s is a %s\n", entry.GetName(), EntryTypeToString(entry.GetType())) + } +} diff --git a/game_mouse_flight.go b/game_mouse_flight.go new file mode 100644 index 0000000..7a87824 --- /dev/null +++ b/game_mouse_flight.go @@ -0,0 +1,144 @@ +package main + +import ( + "math" + + hg "github.com/harfang3d/harfang-go/v3" +) + +// gameplay settings +var ( + settingCameraChaseOffset = hg.NewVec3WithXYZ(0, 0.2, 0) + settingCameraChaseDistance = float32(1) + + settingPlaneSpeed = float32(0.05) + settingPlaneMouseSensitivity = float32(0.5) + vtxLayout = hg.VertexLayoutPosFloatColorFloat() + draw2DProgram *hg.ProgramHandle + draw2DRenderState *hg.RenderState + + cameraNode *hg.Node + planeNode *hg.Node +) + +func draw_circle(viewId uint16, center *hg.Vec3, radius float32, color *hg.Color) { + segmentCount := 32.0 + step := 2.0 * math.Pi / segmentCount + p0 := hg.NewVec3WithXYZ(center.GetX()+radius, center.GetY(), 0) + p1 := hg.NewVec3WithXYZ(0, 0, 0) + + vtx := hg.NewVertices(vtxLayout, int32(segmentCount*2+2)) + + for i := int32(0); i < int32(segmentCount)+1; i += 1 { + p1.SetX(radius*float32(math.Cos(float64(i)*step)) + center.GetX()) + p1.SetY(radius*float32(math.Sin(float64(i)*step)) + center.GetY()) + vtx.Begin(2 * i).SetPos(p0).SetColor0(color).End() + vtx.Begin(2*i + 1).SetPos(p1).SetColor0(color).End() + p0.SetX(p1.GetX()) + p0.SetY(p1.GetY()) + } + + hg.DrawLinesWithRenderState(viewId, vtx, draw2DProgram, draw2DRenderState) + +} + +func updatePlane(mouseXNormd float32, mouseYNormd float32) { + planeTransform := planeNode.GetTransform() + + planePos := planeTransform.GetPos() + planePos = planePos.Add(hg.NormalizeWithVec3V(hg.GetZWithM(planeTransform.GetWorld())).MulWithK(settingPlaneSpeed)) + planePos.SetY(hg.ClampWithV(planePos.GetY(), 0.1, 50)) // floor/ceiling + + planeRot := planeTransform.GetRot() + + nextPlaneRot := hg.NewVec3WithVec3V(planeRot) // make a copy of the plane rotation + nextPlaneRot.SetX(hg.ClampWithV(nextPlaneRot.GetX()+mouseYNormd*-0.03, -0.75, 0.75)) + nextPlaneRot.SetY(nextPlaneRot.GetY() + mouseXNormd*0.03) + nextPlaneRot.SetZ(hg.ClampWithV(mouseXNormd*-0.75, -1.2, 1.2)) + + planeRot = planeRot.Add((nextPlaneRot.Sub(planeRot)).MulWithK(settingPlaneMouseSensitivity)) + + planeTransform.SetPos(planePos) + planeTransform.SetRot(planeRot) + +} + +func updateChaseCamera(targetPos *hg.Vec3) { + cameraTransform := cameraNode.GetTransform() + cameraToTarget := hg.NormalizeWithVec3V(targetPos.Sub(cameraTransform.GetPos())) + + cameraTransform.SetPos(targetPos.Sub(cameraToTarget.MulWithK(settingCameraChaseDistance))) // camera is "distance" away from its target + cameraTransform.SetRot(hg.ToEulerWithM(hg.Mat3LookAt(cameraToTarget))) + +} + +func main() { + hg.InputInit() + hg.WindowSystemInit() + + resX, resY := int32(1280), int32(720) + win := hg.RenderInitWithWindowTitleWidthHeightResetFlags("Harfang - Mouse Flight", resX, resY, hg.RFVSync|hg.RFMSAA8X) + + res := hg.NewPipelineResources() + pipeline := hg.CreateForwardPipeline() + + keyboard := hg.NewKeyboard() + mouse := hg.NewMouse() + + // access to compiled resources + hg.AddAssetsFolder("resources_compiled") + + // 2D drawing helpers + + draw2DProgram = hg.LoadProgramFromAssets("shaders/pos_rgb") + draw2DRenderState = hg.ComputeRenderStateWithDepthTestCulling(hg.BMAlpha, hg.DTLess, hg.FCDisabled) + + // setup game world + scene := hg.NewScene() + hg.LoadSceneFromAssets("playground/playground.scn", scene, res, hg.GetForwardPipelineInfo()) + + planeNode, _ = hg.CreateInstanceFromAssets(scene, hg.TranslationMat4(hg.NewVec3WithXYZ(0, 4, 0)), "paper_plane/paper_plane.scn", res, hg.GetForwardPipelineInfo()) + cameraNode = hg.CreateCamera(scene, hg.TranslationMat4(hg.NewVec3WithXYZ(0, 4, -5)), 0.01, 1000) + + scene.SetCurrentCamera(cameraNode) + + // game loop + for !hg.ReadKeyboard().Key(hg.KEscape) && hg.IsWindowOpen(win) { + dt := hg.TickClock() // tick clock, retrieve elapsed clock since last call + + // update mouse/keyboard devices + keyboard.Update() + mouse.Update() + + // compute ratio corrected normalized mouse position + mouse_x, mouse_y := mouse.X(), mouse.Y() + + aspect_ratio := hg.ComputeAspectRatioX(float32(resX), float32(resY)) + mouseXNormd, mouseYNormd := (float32(mouse_x)/float32(resX)-0.5)*aspect_ratio.GetX(), (float32(mouse_y)/float32(resY)-0.5)*aspect_ratio.GetY() + + // update gameplay elements (plane & camera) + updatePlane(mouseXNormd, mouseYNormd) + updateChaseCamera(hg.NewVec3WithVec4V(planeNode.GetTransform().GetWorld().MulWithVec4V(hg.NewVec4WithVec3V(settingCameraChaseOffset)))) + + // update scene and submit it to render pipeline + scene.Update(dt) + + viewId := uint16(0) + hg.SubmitSceneToPipelineWithFovAxisIsHorizontal(&viewId, scene, hg.NewIntRectWithSxSyExEy(0, 0, resX, resY), true, pipeline, res) + + // draw 2D GUI + hg.SetView2DWithZnearZfarFlagsColorDepthStencilYUp(viewId, 0, 0, resX, resY, -1, 1, hg.CFDepth, hg.ColorGetBlack(), 1, 0, true) + draw_circle(viewId, hg.NewVec3WithXYZ(float32(mouse_x), float32(mouse_y), 0), 20, hg.ColorGetWhite()) // display mouse cursor + + // end of frame + hg.Frame() + hg.UpdateWindow(win) + + } + + hg.RenderShutdown() + hg.DestroyWindow(win) + + hg.WindowSystemShutdown() + hg.InputShutdown() +} diff --git a/imgui_basic.go b/imgui_basic.go new file mode 100644 index 0000000..346ae95 --- /dev/null +++ b/imgui_basic.go @@ -0,0 +1,40 @@ +package main + +import ( + hg "github.com/harfang3d/harfang-go/v3" +) + +func main() { + hg.InputInit() + hg.WindowSystemInit() + + res_x, res_y := int32(1280), int32(720) + win := hg.RenderInitWithWindowTitleWidthHeightResetFlags("Harfang - ImGui Basics", res_x, res_y, hg.RFVSync) + + // initialize ImGui + hg.AddAssetsFolder("resources_compiled") + + imgui_prg := hg.LoadProgramFromAssets("core/shader/imgui") + imgui_img_prg := hg.LoadProgramFromAssets("core/shader/imgui_image") + + hg.ImGuiInit(10, imgui_prg, imgui_img_prg) + + // main loop + for !hg.ReadKeyboard().Key(hg.KEscape) && hg.IsWindowOpen(win) { + + hg.ImGuiBeginFrame(res_x, res_y, hg.TickClock(), hg.ReadMouse(), hg.ReadKeyboard()) + + if hg.ImGuiBegin("Window") { + hg.ImGuiText("Hello World!") + } + hg.ImGuiEnd() + + hg.SetView2DWithZnearZfarFlagsColorDepthStencil(0, 0, 0, res_x, res_y, -1, 1, hg.CFColor|hg.CFDepth, hg.ColorGetBlack(), 1, 0) + hg.ImGuiEndFrameWithViewId(0) + + hg.Frame() + hg.UpdateWindow(win) + } + hg.RenderShutdown() + hg.DestroyWindow(win) +} diff --git a/imgui_edit.go b/imgui_edit.go new file mode 100644 index 0000000..cd29015 --- /dev/null +++ b/imgui_edit.go @@ -0,0 +1,78 @@ +package main + +import ( + "math" + + hg "github.com/harfang3d/harfang-go/v3" +) + +func main() { + hg.InputInit() + hg.WindowSystemInit() + + res_x, res_y := int32(1280), int32(720) + win := hg.RenderInitWithWindowTitleWidthHeightResetFlags("Harfang - ImGui Edit", res_x, res_y, hg.RFVSync) + + hg.AddAssetsFolder("resources_compiled") + + // initialize ImGui + imgui_prg := hg.LoadProgramFromAssets("core/shader/imgui") + imgui_img_prg := hg.LoadProgramFromAssets("core/shader/imgui_image") + + hg.ImGuiInit(10, imgui_prg, imgui_img_prg) + + imgui_output_view := int32(255) + imgui_view_clear_color := hg.NewColorWithRGB(0, 0, 0) + imgui_clear_color_preset := int32(0) + imguiOpen := true + + // main loop + for !hg.ReadKeyboard().Key(hg.KEscape) && hg.IsWindowOpen(win) { + dt := hg.TickClock() + + // ImGui frame + hg.ImGuiBeginFrame(res_x, res_y, dt, hg.ReadMouse(), hg.ReadKeyboard()) + + hg.ImGuiSetNextWindowPosCenterWithCondition(hg.ImGuiCondOnce) + + if hg.ImGuiBeginWithOpenFlags("ImGui Controls", &imguiOpen, hg.ImGuiWindowFlagsAlwaysAutoResize) { + val_modified := hg.ImGuiComboWithSliceOfItems("Set Clear Color", &imgui_clear_color_preset, hg.GoSliceOfstring{"Red", "Green", "Blue"}) + + // apply preset if a combo entry was selected + if val_modified { + if imgui_clear_color_preset == 0 { + imgui_view_clear_color = hg.NewColorWithRGB(1, 0, 0) + } else if imgui_clear_color_preset == 1 { + imgui_view_clear_color = hg.NewColorWithRGB(0, 1, 0) + } else { + imgui_view_clear_color = hg.NewColorWithRGB(0, 0, 1) + } + } + + // reset clear color to black on button click + if hg.ImGuiButton("Reset Clear Color") { + imgui_view_clear_color = hg.ColorGetBlack() + } + + // custom clear color edit + val_modified = hg.ImGuiColorEdit("Edit Clear Color", imgui_view_clear_color) + + // edit the ImGui output view + val_modified = hg.ImGuiInputInt("ImGui Output View", &imgui_output_view) + if val_modified { + imgui_output_view = int32(math.Max(0.0, math.Min(float64(imgui_output_view), 255.0))) // keep output view in [0;255] range} + } + } + hg.ImGuiEnd() + + hg.SetView2DWithZnearZfarFlagsColorDepthStencil(uint16(imgui_output_view), 0, 0, res_x, res_y, -1, 0, hg.CFColor|hg.CFDepth, imgui_view_clear_color, 1, 0) + hg.ImGuiEndFrameWithViewId(uint16(imgui_output_view)) + + // rendering frame + hg.Frame() + + hg.UpdateWindow(win) + } + hg.RenderShutdown() + hg.DestroyWindow(win) +} diff --git a/imgui_mouse_capture.go b/imgui_mouse_capture.go new file mode 100644 index 0000000..91d3436 --- /dev/null +++ b/imgui_mouse_capture.go @@ -0,0 +1,57 @@ +package main + +import ( + hg "github.com/harfang3d/harfang-go/v3" +) + +func main() { + hg.InputInit() + hg.WindowSystemInit() + + res_x, res_y := int32(1280), int32(720) + win := hg.RenderInitWithWindowTitleWidthHeightResetFlags("Harfang - ImGui Mouse Capture", res_x, res_y, hg.RFVSync) + + hg.AddAssetsFolder("resources_compiled") + + hg.ImGuiInit(10, hg.LoadProgramFromAssets("core/shader/imgui"), hg.LoadProgramFromAssets("core/shader/imgui_image")) + text_value := "Clicking into this field will not clear the screen in red." + + mouse := hg.NewMouse() + keyboard := hg.NewKeyboard() + + for !hg.ReadKeyboard().Key(hg.KEscape) && hg.IsWindowOpen(win) { + mouse.Update() + keyboard.Update() + + dt := hg.TickClock() + hg.ImGuiBeginFrame(res_x, res_y, dt, mouse.GetState(), keyboard.GetState()) + + clear_color := hg.ColorGetBlack() + if hg.ImGuiWantCaptureMouse() { + clear_color = hg.ColorGetBlack() // black background if ImGui has mouse capture + } else { + if mouse.Down(int32(hg.MB0)) { + clear_color = hg.ColorGetRed() + } + } + + hg.SetView2DWithZnearZfarFlagsColorDepthStencil(0, 0, 0, res_x, res_y, -1, 0, hg.CFColor|hg.CFDepth, clear_color, 1, 0) + + hg.ImGuiSetNextWindowPosCenterWithCondition(hg.ImGuiCondOnce) + hg.ImGuiSetNextWindowSizeWithCondition(hg.NewVec2WithXY(700, 96), hg.ImGuiCondOnce) + + if hg.ImGuiBegin("Detecting ImGui mouse capture") { + hg.ImGuiTextWrapped("Click outside of the GUI to clear the screen in red.") + hg.ImGuiSeparator() + _, text_value_temp := hg.ImGuiInputText("Text Input", text_value, 4096) + text_value = *text_value_temp + } + hg.ImGuiEnd() + + hg.ImGuiEndFrameWithViewId(0) + + hg.Frame() + hg.UpdateWindow(win) + } + hg.DestroyWindow(win) +} diff --git a/input_list_devices.go b/input_list_devices.go new file mode 100644 index 0000000..3bc5137 --- /dev/null +++ b/input_list_devices.go @@ -0,0 +1,36 @@ +package main + +import ( + "fmt" + "strings" + + hg "github.com/harfang3d/harfang-go/v3" +) + +func main() { + hg.InputInit() + + names := hg.GetMouseNames() + fmt.Print("Mouse device names: ") + namesStr := []string{} + for i := int32(0); i < names.Size(); i += 1 { + namesStr = append(namesStr, names.At(i)) + } + fmt.Println(strings.Join(namesStr, ", ")) + + names = hg.GetKeyboardNames() + fmt.Print("Keyboard device names: ") + namesStr = []string{} + for i := int32(0); i < names.Size(); i += 1 { + namesStr = append(namesStr, names.At(i)) + } + fmt.Println(strings.Join(namesStr, ", ")) + + names = hg.GetGamepadNames() + fmt.Print("Gamepad device names: ") + namesStr = []string{} + for i := int32(0); i < names.Size(); i += 1 { + namesStr = append(namesStr, names.At(i)) + } + fmt.Println(strings.Join(namesStr, ", ")) +} diff --git a/input_read_gamepad.go b/input_read_gamepad.go new file mode 100644 index 0000000..6ffa926 --- /dev/null +++ b/input_read_gamepad.go @@ -0,0 +1,54 @@ +package main + +import ( + "fmt" + "math" + + hg "github.com/harfang3d/harfang-go/v3" +) + +func main() { + hg.InputInit() + hg.WindowSystemInit() + + win := hg.NewWindowWithTitleWidthHeight("Harfang - Read Gamepad", 320, 200) + + gamepad := hg.NewGamepad() + + for !hg.ReadKeyboard().Key(hg.KEscape) && hg.IsWindowOpen(win) { + gamepad.Update() + + if gamepad.Connected() { + fmt.Println("Gamepad slot 0 was just connected") + } + if gamepad.Disconnected() { + fmt.Println("Gamepad slot 0 was just disconnected") + } + + if gamepad.Pressed(hg.GBButtonA) { + fmt.Println("Gamepad button A pressed") + } + if gamepad.Pressed(hg.GBButtonB) { + fmt.Println("Gamepad button B pressed") + } + if gamepad.Pressed(hg.GBButtonX) { + fmt.Println("Gamepad button X pressed") + } + if gamepad.Pressed(hg.GBButtonY) { + fmt.Println("Gamepad button Y pressed") + } + + axis_left_x := gamepad.Axes(hg.GALeftX) + if math.Abs(float64(axis_left_x)) > 0.1 { + fmt.Println("Gamepad axis left X: %v", axis_left_x) + } + + axis_left_y := gamepad.Axes(hg.GALeftY) + if math.Abs(float64(axis_left_y)) > 0.1 { + fmt.Println("Gamepad axis left Y: %v", axis_left_y) + } + + hg.UpdateWindow(win) + } + hg.DestroyWindow(win) +} diff --git a/input_read_keyboard_advanced.go b/input_read_keyboard_advanced.go new file mode 100644 index 0000000..55f6e1a --- /dev/null +++ b/input_read_keyboard_advanced.go @@ -0,0 +1,23 @@ +package main + +import ( + "fmt" + + hg "github.com/harfang3d/harfang-go/v3" +) + +func main() { + hg.InputInit() + + keyboard := hg.NewKeyboardWithName("raw") // note: the "raw" device can be queried without an open window, use "default" otherwise + + for !keyboard.Pressed(hg.KEscape) { + keyboard.Update() + + for key := hg.Key(0); key < hg.KLast; key += 1 { + if keyboard.Released(key) { // will react on key release using the current and previous keyboard state + fmt.Println("Key released: ", key) + } + } + } +} diff --git a/input_read_keyboard_basic.go b/input_read_keyboard_basic.go new file mode 100644 index 0000000..dff1cd0 --- /dev/null +++ b/input_read_keyboard_basic.go @@ -0,0 +1,24 @@ +package main + +import ( + "fmt" + + hg "github.com/harfang3d/harfang-go/v3" +) + +func main() { + hg.InputInit() + for { + state := hg.ReadKeyboardWithName("raw") // note: the "raw" device can be queried without an open window, use "default" otherwise + + for key := hg.Key(0); key < hg.KLast; key += 1 { + if state.Key(key) { + fmt.Println("Key down: ", key) + } + } + + if state.Key(hg.KEscape) { + break + } + } +} diff --git a/input_read_mouse_advanced.go b/input_read_mouse_advanced.go new file mode 100644 index 0000000..60cf60a --- /dev/null +++ b/input_read_mouse_advanced.go @@ -0,0 +1,32 @@ +package main + +import ( + "fmt" + + hg "github.com/harfang3d/harfang-go/v3" +) + +func main() { + hg.InputInit() + mouse := hg.NewMouseWithName("raw") + + for !hg.ReadKeyboard().Key(hg.KEscape) { // note: the "raw" device can be queried without an open window, use "default" otherwise + mouse.Update() + + dt_x := mouse.DtX() + dt_y := mouse.DtY() + + if dt_x != 0 || dt_y != 0 { + fmt.Println("Mouse delta X=%d delta Y=%d", dt_x, dt_y) + } + + for i := int32(0); i < 3; i += 1 { + if mouse.Pressed(int32(hg.MB0) + i) { + fmt.Println("Mouse button %d pressed", i) + } + if mouse.Released(int32(hg.MB0) + i) { + fmt.Println("Mouse button %d released", i) + } + } + } +} diff --git a/input_read_mouse_basic.go b/input_read_mouse_basic.go new file mode 100644 index 0000000..7c06413 --- /dev/null +++ b/input_read_mouse_basic.go @@ -0,0 +1,25 @@ +package main + +import ( + "fmt" + + hg "github.com/harfang3d/harfang-go/v3" +) + +func main() { + hg.InputInit() + for !hg.ReadKeyboardWithName("raw").Key(hg.KEscape) { // note: the "raw" device can be queried without an open window, use "default" otherwise + state := hg.ReadMouseWithName("raw") + + x := state.X() + y := state.Y() + + button_0 := state.Button(hg.MB0) + button_1 := state.Button(hg.MB1) + button_2 := state.Button(hg.MB2) + + wheel := state.Wheel() + + fmt.Println("Mouse state: X=%d Y=%d B0=%v B1=%v B2=%v Wheel=%d", x, y, button_0, button_1, button_2, wheel) + } +} diff --git a/material_update_value.go b/material_update_value.go new file mode 100644 index 0000000..27bbc71 --- /dev/null +++ b/material_update_value.go @@ -0,0 +1,85 @@ +package main + +import ( + hg "github.com/harfang3d/harfang-go/v3" +) + +func main() { + hg.InputInit() + hg.WindowSystemInit() + + res_x, res_y := int32(1280), int32(720) + win := hg.RenderInitWithWindowTitleWidthHeightResetFlags("Modify material pipeline shader ", res_x, res_y, hg.RFVSync|hg.RFMSAA4X) + + hg.AddAssetsFolder("resources_compiled") + + pipeline := hg.CreateForwardPipeline() + res := hg.NewPipelineResources() + + // create models + vtx_layout := hg.VertexLayoutPosFloatNormUInt8() + + cube_mdl := hg.CreateCubeModel(vtx_layout, 1, 1, 1) + cube_ref := res.AddModel("cube", cube_mdl) + ground_mdl := hg.CreateCubeModel(vtx_layout, 100, 0.01, 100) + ground_ref := res.AddModel("ground", ground_mdl) + + // create materials + shader := hg.LoadPipelineProgramRefFromAssets("core/shader/default.hps", res, hg.GetForwardPipelineInfo()) + + mat_cube := hg.CreateMaterialWithValueName0Value0ValueName1Value1(shader, "uDiffuseColor", hg.NewVec4WithXYZ(1, 1, 1), "uSpecularColor", hg.NewVec4WithXYZ(1, 1, 1)) + mat_ground := hg.CreateMaterialWithValueName0Value0ValueName1Value1(shader, "uDiffuseColor", hg.NewVec4WithXYZ(1, 1, 1), "uSpecularColor", hg.NewVec4WithXYZ(0.1, 0.1, 0.1)) + + // setup scene + scene := hg.NewScene() + + cam := hg.CreateCamera(scene, hg.Mat4LookAt(hg.NewVec3WithXYZ(-1.30, 0.27, -2.47), hg.NewVec3WithXYZ(0, 0.5, 0)), 0.01, 1000) + scene.SetCurrentCamera(cam) + + hg.CreateLinearLightWithDiffuseSpecularPriority(scene, hg.TransformationMat4(hg.NewVec3WithXYZ(0, 2, 0), hg.Deg3(27.5, -97.6, 16.6)), hg.ColorI(64, 64, 64), hg.ColorI(64, 64, 64), 10) + hg.CreateSpotLightWithDiffuseSpecularPriorityShadowTypeShadowBias(scene, hg.TransformationMat4(hg.NewVec3WithXYZ(5, 4, -5), hg.Deg3(19, -45, 0)), 0, hg.Deg(5), hg.Deg(30), hg.ColorI(255, 255, 255), hg.ColorI(255, 255, 255), 10, hg.LSTMap, 0.0001) + + cube_node := hg.CreateObjectWithSliceOfMaterials(scene, hg.TranslationMat4(hg.NewVec3WithXYZ(0, 0.5, 0)), cube_ref, hg.GoSliceOfMaterial{mat_cube}) + hg.CreateObjectWithSliceOfMaterials(scene, hg.TranslationMat4(hg.NewVec3WithXYZ(0, 0, 0)), ground_ref, hg.GoSliceOfMaterial{mat_ground}) + + // material update states + mat_has_texture := false + mat_update_delay := int64(0) + + texture_ref := hg.LoadTextureFromAssetsWithFlagsResources("textures/squares.png", 0, res) + + // main loop + for !hg.ReadKeyboard().Key(hg.KEscape) && hg.IsWindowOpen(win) { + dt := hg.TickClock() + + mat_update_delay = mat_update_delay - dt + + if mat_update_delay <= 0 { + // set or remove cube node material texture + mat := cube_node.GetObject().GetMaterial(0) + + if mat_has_texture { + hg.SetMaterialTexture(mat, "uDiffuseMap", &hg.InvalidTextureRef, 0) + } else { + hg.SetMaterialTexture(mat, "uDiffuseMap", texture_ref, 0) + } + + // update the pipeline shader variant according to the material uniform values + hg.UpdateMaterialPipelineProgramVariant(mat, res) + + // reset delay and flip flag + mat_update_delay = mat_update_delay + hg.TimeFromSec(1) + mat_has_texture = !mat_has_texture + } + + scene.Update(dt) + + viewId := uint16(0) + hg.SubmitSceneToPipelineWithFovAxisIsHorizontal(&viewId, scene, hg.NewIntRectWithSxSyExEy(0, 0, res_x, res_y), true, pipeline, res) + + hg.Frame() + hg.UpdateWindow(win) + } + hg.RenderShutdown() + hg.DestroyWindow(win) +} diff --git a/physics_impulse.go b/physics_impulse.go new file mode 100644 index 0000000..53cb2ba --- /dev/null +++ b/physics_impulse.go @@ -0,0 +1,96 @@ +package main + +import ( + hg "github.com/harfang3d/harfang-go/v3" +) + +func main() { + hg.InputInit() + hg.WindowSystemInit() + + res_x, res_y := int32(1280), int32(720) + win := hg.RenderInitWithWindowTitleWidthHeightResetFlags("Harfang - Physics Force/Impulse (Press space to alternate)", res_x, res_y, hg.RFVSync|hg.RFMSAA4X) + + pipeline := hg.CreateForwardPipeline() + res := hg.NewPipelineResources() + + // create models + vtx_layout := hg.VertexLayoutPosFloatNormUInt8() + + cube_mdl := hg.CreateCubeModel(vtx_layout, 1, 1, 1) + cube_ref := res.AddModel("cube", cube_mdl) + + ground_mdl := hg.CreateCubeModel(vtx_layout, 50, 0.01, 50) + ground_ref := res.AddModel("ground", ground_mdl) + + // create material + prg_ref := hg.LoadPipelineProgramRefFromFile("resources_compiled/core/shader/default.hps", res, hg.GetForwardPipelineInfo()) + mat := hg.CreateMaterialWithValueName0Value0ValueName1Value1(prg_ref, "uDiffuseColor", hg.NewVec4WithXYZ(1, 1, 1), "uSpecularColor", hg.NewVec4WithXYZ(1, 1, 1)) + + // setup scene + scene := hg.NewScene() + + cam := hg.CreateCamera(scene, hg.TransformationMat4(hg.NewVec3WithXYZ(0, 1.5, -5), hg.NewVec3WithXYZ(hg.Deg(10), 0, 0)), 0.01, 1000) + scene.SetCurrentCamera(cam) + + hg.CreateLinearLightWithDiffuseSpecularPriorityShadowTypeShadowBiasPssmSplit(scene, hg.TransformationMat4(hg.NewVec3WithXYZ(0, 0, 0), hg.NewVec3WithXYZ(hg.Deg(30), hg.Deg(59), 0)), hg.NewColorWithRGB(1, 1, 1), hg.NewColorWithRGB(1, 1, 1), 10, hg.LSTMap, 0.002, hg.NewVec4WithXYZW(2, 4, 10, 16)) + + cube_node := hg.CreatePhysicCubeWithSliceOfMaterialsMass(scene, hg.NewVec3WithXYZ(1, 1, 1), hg.TranslationMat4(hg.NewVec3WithXYZ(0, 1.5, 0)), cube_ref, hg.GoSliceOfMaterial{mat}, 2) + hg.CreatePhysicCubeWithSliceOfMaterialsMass(scene, hg.NewVec3WithXYZ(100, 0.02, 100), hg.TranslationMat4(hg.NewVec3WithXYZ(0, -0.005, 0)), ground_ref, hg.GoSliceOfMaterial{mat}, 0) + + clocks := hg.NewSceneClocks() + + // scene physics + physics := hg.NewSceneBullet3Physics() + physics.SceneCreatePhysicsFromAssets(scene) + physics_step := hg.TimeFromSecF(1.0 / 60.0) + + // main loop + keyboard := hg.NewKeyboard() + + use_force := true + + for !hg.ReadKeyboard().Key(hg.KEscape) && hg.IsWindowOpen(win) { + keyboard.Update() + + dt := hg.TickClock() + + if keyboard.Pressed(hg.KSpace) { + use_force = !use_force + } + + world_pos := hg.GetT(cube_node.GetTransform().GetWorld()) + dist_to_ground := world_pos.GetY() - 0.5 + + if dist_to_ground < 1.0 { + k := -(dist_to_ground - 1.0) + + if use_force { + F := hg.NewVec3WithXYZ(0, 1, 0).MulWithK(k * 80) // apply a force inversely proportional to the distance to the ground + physics.NodeAddForceWithWorldPos(cube_node, F, world_pos) + } else { + stiffness := 10 + + cur_velocity := physics.NodeGetLinearVelocity(cube_node) + tgt_velocity := hg.NewVec3WithXYZ(0, 1, 0).MulWithK(k * float32(stiffness)) // compute a velocity that brings us to 1 meter above the ground + + I := tgt_velocity.Sub(cur_velocity) // an impulse is an instantaneous change in velocity + physics.NodeAddImpulseWithWorldPos(cube_node, I, world_pos) + } + } + physics.NodeWake(cube_node) + + hg.SceneUpdateSystemsWithPhysicsStepMaxPhysicsStep(scene, clocks, dt, physics, physics_step, 3) + viewId := uint16(0) + hg.SubmitSceneToPipelineWithFovAxisIsHorizontal(&viewId, scene, hg.NewIntRectWithSxSyExEy(0, 0, res_x, res_y), true, pipeline, res) + + hg.Frame() + hg.UpdateWindow(win) + } + + hg.RenderShutdown() + hg.DestroyWindow(win) + + hg.WindowSystemShutdown() + hg.InputShutdown() +} diff --git a/physics_kapla.go b/physics_kapla.go new file mode 100644 index 0000000..a3525d2 --- /dev/null +++ b/physics_kapla.go @@ -0,0 +1,133 @@ +package main + +import ( + "math" + "runtime" + "runtime/debug" + + hg "github.com/harfang3d/harfang-go/v3" +) + +func fillRing(scn *hg.Scene, material *hg.Material, kaplaRef *hg.ModelRef, width float32, height float32, length float32, r float32, ringY float32, size float32, rAdjust float32, yOff float32, x float32, y float32, z float32) { + step := math.Asin(float64((size*1.01)/2.0/(r-rAdjust))) * 2.0 + cubeCount := math.Floor((2.0 * math.Pi) / step) + error := 2.0*math.Pi - step*cubeCount + step += error / cubeCount // distribute error + + for a := 0.0; a < 2.0*math.Pi-error; a += step { + world := hg.TransformationMat4(hg.NewVec3WithXYZ(float32(math.Cos(a))*r+x, ringY, float32(math.Sin(a))*r+z), hg.NewVec3WithXYZ(0, float32(-a)+yOff, 0)) + hg.CreatePhysicCubeWithSliceOfMaterialsMass(scn, hg.NewVec3WithXYZ(width, height, length), world, kaplaRef, hg.GoSliceOfMaterial{material}, 0.1) + } +} + +func addKaplaTower(scn *hg.Scene, ressources *hg.PipelineResources, width float32, height float32, length float32, radius float32, material *hg.Material, levelCount int, x float32, y float32, z float32, vtxLayout *hg.VertexLayout) { + // Create a Kapla tower, return a list of created nodes + levelY := y + height/2.0 + + kaplaMdl := hg.CreateCubeModel(vtxLayout, width, height, length) + kaplaRef := ressources.AddModel("kapla", kaplaMdl) + + for i := 0; i < levelCount/2; i++ { + fillRing(scn, material, kaplaRef, width, height, length, radius-length/2.0, levelY, width, length/2.0, math.Pi/2.0, x, y, z) + levelY += height + fillRing(scn, material, kaplaRef, width, height, length, radius-length+width/2.0, levelY, length, width/2.0, 0, x, y, z) + fillRing(scn, material, kaplaRef, width, height, length, radius-width/2.0, levelY, length, width/2.0, 0, x, y, z) + levelY += height + } +} + +func main() { + debug.SetGCPercent(-1) + + hg.InputInit() + hg.WindowSystemInit() + + resX, resY := int32(1280), int32(720) + + win := hg.RenderInitWithWindowTitleWidthHeightResetFlags("Harfang - Kapla", resX, resY, hg.RFVSync|hg.RFMSAA4X) + + hg.AddAssetsFolder("resources_compiled") + + pipeline := hg.CreateForwardPipeline() + res := hg.NewPipelineResources() + + // create models + vtxLayout := hg.VertexLayoutPosFloatNormUInt8() + + sphereMdl := hg.CreateSphereModel(vtxLayout, 0.5, 12, 24) + sphereRef := res.AddModel("sphere", sphereMdl) + + // Create material + prgRef := hg.LoadPipelineProgramRefFromAssets("core/shader/pbr.hps", res, hg.GetForwardPipelineInfo()) + + matCube := hg.CreateMaterialWithValueName0Value0ValueName1Value1(prgRef, "uBaseOpacityColor", hg.Vec4I(255, 255, 56), "uOcclusionRoughnessMetalnessColor", hg.NewVec4WithXYZ(1, 0.658, 1)) + matGround := hg.CreateMaterialWithValueName0Value0ValueName1Value1(prgRef, "uBaseOpacityColor", hg.Vec4I(171, 255, 175), "uOcclusionRoughnessMetalnessColor", hg.NewVec4WithXYZ(1, 1, 1)) + matSpheres := hg.CreateMaterialWithValueName0Value0ValueName1Value1(prgRef, "uBaseOpacityColor", hg.Vec4I(255, 71, 75), "uOcclusionRoughnessMetalnessColor", hg.NewVec4WithXYZ(1, 0.5, 0.1)) + + // Setup scene + scene := hg.NewScene() + scene.GetCanvas().SetColor(hg.ColorI(200, 210, 208)) + scene.GetEnvironment().SetAmbient(hg.ColorGetBlack()) + + cam := hg.CreateCamera(scene, hg.Mat4GetIdentity(), 0.01, 1000) + scene.SetCurrentCamera(cam) + + hg.CreateLinearLightWithDiffuseSpecularPriorityShadowTypeShadowBiasPssmSplit(scene, hg.TransformationMat4(hg.NewVec3WithXYZ(0, 0, 0), hg.Deg3(19, 59, 0)), hg.NewColorWithRGBA(1.5, 0.9, 1.2, 1), hg.NewColorWithRGBA(1.5, 0.9, 1.2, 1), 10, hg.LSTMap, 0.002, hg.NewVec4WithXYZW(8, 20, 40, 120)) + hg.CreatePointLightWithDiffuseSpecularPriority(scene, hg.TranslationMat4(hg.NewVec3WithXYZ(30, 20, 25)), 100, hg.NewColorWithRGBA(0.8, 0.5, 0.4, 1), hg.NewColorWithRGBA(0.8, 0.5, 0.4, 1), 0) + + mdlRef := res.AddModel("ground", hg.CreateCubeModel(vtxLayout, 200, 0.1, 200)) + hg.CreatePhysicCubeWithSliceOfMaterialsMass(scene, hg.NewVec3WithXYZ(200, 0.1, 200), hg.TranslationMat4(hg.NewVec3WithXYZ(0, -0.5, 0)), mdlRef, hg.GoSliceOfMaterial{matGround}, 0) + + addKaplaTower(scene, res, 0.5, 2, 2, 6, matCube, 12, -12, 0, 0, vtxLayout) + addKaplaTower(scene, res, 0.5, 2, 2, 6, matCube, 12, 12, 0, 0, vtxLayout) + + clocks := hg.NewSceneClocks() + + // Input devices and fps controller states + keyboard := hg.NewKeyboard() + mouse := hg.NewMouse() + + camPos := hg.NewVec3WithXYZ(28.3, 31.8, 26.9) + camRot := hg.NewVec3WithXYZ(0.6, -2.38, 0) + + // Setup physics + physics := hg.NewSceneBullet3Physics() + physics.SceneCreatePhysicsFromAssets(scene) + physicsStep := hg.TimeFromSecF(1.0 / 60.0) + + // Main loop + for !hg.ReadKeyboard().Key(hg.KEscape) && hg.IsWindowOpen(win) { + keyboard.Update() + mouse.Update() + + dt := hg.TickClock() + + speed := float32(8.0) + if keyboard.Down(hg.KLShift) { + speed = 20.0 + } + hg.FpsController(keyboard, mouse, camPos, camRot, speed, dt) + + cam.GetTransform().SetPos(camPos) + cam.GetTransform().SetRot(camRot) + + if keyboard.Pressed(hg.KSpace) { + node := hg.CreatePhysicSphereWithSliceOfMaterialsMass(scene, 0.5, hg.TranslationMat4(camPos), sphereRef, hg.GoSliceOfMaterial{matSpheres}, 0.5) + physics.NodeCreatePhysicsFromAssets(node) + physics.NodeAddImpulseWithWorldPos(node, hg.GetZWithM(cam.GetTransform().GetWorld()).MulWithK(25), camPos) + } + + // Display scene + viewID := uint16(0) + hg.SceneUpdateSystemsWithPhysicsStepMaxPhysicsStep(scene, clocks, dt, physics, physicsStep, 1) + hg.SubmitSceneToPipelineWithFovAxisIsHorizontal(&viewID, scene, hg.NewIntRectWithSxSyExEy(0, 0, resX, resY), true, pipeline, res) + + hg.Frame() + hg.UpdateWindow(win) + runtime.GC() + } + + hg.DestroyForwardPipeline(pipeline) + hg.RenderShutdown() + hg.DestroyWindow(win) +} diff --git a/physics_manual_setup.go b/physics_manual_setup.go new file mode 100644 index 0000000..1e90336 --- /dev/null +++ b/physics_manual_setup.go @@ -0,0 +1,75 @@ +package main + +import ( + hg "github.com/harfang3d/harfang-go/v3" +) + +func main() { + hg.InputInit() + hg.WindowSystemInit() + + res_x, res_y := int32(1280), int32(720) + win := hg.RenderInitWithWindowTitleWidthHeightResetFlags("Harfang - Node Physics Setup", res_x, res_y, hg.RFVSync|hg.RFMSAA4X) + + pipeline := hg.CreateForwardPipeline() + res := hg.NewPipelineResources() + + // create models + vtx_mdl := hg.VertexLayoutPosFloatNormUInt8() + + cube_mdl := hg.CreateCubeModel(vtx_mdl, 1, 1, 1) + cube_ref := res.AddModel("cube", cube_mdl) + + ground_mdl := hg.CreateCubeModel(vtx_mdl, 50, 0.01, 50) + ground_ref := res.AddModel("ground", ground_mdl) + + // create materials + prg_ref := hg.LoadPipelineProgramRefFromFile("resources_compiled/core/shader/default.hps", res, hg.GetForwardPipelineInfo()) + mat := hg.CreateMaterialWithValueName0Value0ValueName1Value1(prg_ref, "uDiffuseColor", hg.NewVec4WithXYZW(0.5, 0.5, 0.5, 1), "uSpecularColor", hg.NewVec4WithXYZW(0.0, 0.0, 0.0, 0.1)) + + // setup scene + scene := hg.NewScene() + + cam := hg.CreateCamera(scene, hg.TransformationMat4(hg.NewVec3WithXYZ(0, 1, -5), hg.Deg3(5, 0, 0)), 0.01, 1000) + scene.SetCurrentCamera(cam) + + hg.CreatePointLight(scene, hg.TranslationMat4(hg.NewVec3WithXYZ(6, 4, -6)), 0) + hg.CreatePhysicCubeWithSliceOfMaterialsMass(scene, hg.NewVec3WithXYZ(100, 0.02, 100), hg.TranslationMat4(hg.NewVec3WithXYZ(0, -0.005, 0)), ground_ref, hg.GoSliceOfMaterial{mat}, 0) + + clocks := hg.NewSceneClocks() + + // setup physic cube + cube_node := hg.CreateObjectWithSliceOfMaterials(scene, hg.TransformationMat4(hg.NewVec3WithXYZ(0, 2.5, 0), hg.NewVec3WithXYZ(0, 0, 0)), cube_ref, hg.GoSliceOfMaterial{mat}) + + rb := scene.CreateRigidBody() + rb.SetType(hg.RBTDynamic) + + collision := scene.CreateCollision() + collision.SetType(hg.CTCube) + collision.SetSize(hg.NewVec3WithXYZ(1, 1, 1)) + collision.SetMass(1) + + cube_node.SetRigidBody(rb) + cube_node.SetCollision(0, collision) + + // scene physics + physics := hg.NewSceneBullet3Physics() + physics.SceneCreatePhysicsFromAssets(scene) + + // main loop + for !hg.ReadKeyboard().Key(hg.KEscape) && hg.IsWindowOpen(win) { + dt := hg.TickClock() + + hg.SceneUpdateSystemsWithPhysicsStepMaxPhysicsStep(scene, clocks, dt, physics, hg.TimeFromSecF(1.0/60.0), 1) + viewId := uint16(0) + hg.SubmitSceneToPipelineWithFovAxisIsHorizontal(&viewId, scene, hg.NewIntRectWithSxSyExEy(0, 0, res_x, res_y), true, pipeline, res) + + hg.Frame() + hg.UpdateWindow(win) + } + hg.RenderShutdown() + hg.DestroyWindow(win) + + hg.WindowSystemShutdown() + hg.InputShutdown() +} diff --git a/physics_overrides_matrix.go b/physics_overrides_matrix.go new file mode 100644 index 0000000..9ecbd78 --- /dev/null +++ b/physics_overrides_matrix.go @@ -0,0 +1,123 @@ +package main + +import ( + hg "github.com/harfang3d/harfang-go/v3" +) + +func main() { + hg.InputInit() + hg.WindowSystemInit() + + res_x, res_y := int32(1280), int32(720) + win := hg.RenderInitWithWindowTitleWidthHeightResetFlags("Harfang - Physics Matrix Interaction", res_x, res_y, hg.RFVSync|hg.RFMSAA4X) + + pipeline := hg.CreateForwardPipeline() + res := hg.NewPipelineResources() + + hg.ImGuiInit(10, hg.LoadProgramFromFile("resources_compiled/core/shader/imgui"), hg.LoadProgramFromFile("resources_compiled/core/shader/imgui_image")) + + // physics debug + vtx_line_layout := hg.VertexLayoutPosFloatColorUInt8() + line_shader := hg.LoadProgramFromFile("resources_compiled/shaders/pos_rgb") + + // create models + vtx_layout := hg.VertexLayoutPosFloatNormUInt8() + + cube_mdl := hg.CreateCubeModel(vtx_layout, 1, 1, 1) + cube_ref := res.AddModel("cube", cube_mdl) + ground_mdl := hg.CreateCubeModel(vtx_layout, 100, 0.02, 100) + ground_ref := res.AddModel("ground", ground_mdl) + + prg_ref := hg.LoadPipelineProgramRefFromFile("resources_compiled/core/shader/default.hps", res, hg.GetForwardPipelineInfo()) + + // create material + mat := hg.CreateMaterialWithValueName0Value0ValueName1Value1(prg_ref, "uDiffuseColor", hg.NewVec4WithXYZ(0.5, 0.5, 0.5), "uSpecularColor", hg.NewVec4WithXYZ(1, 1, 1)) + + // setup scene + scene := hg.NewScene() + + cam_mat := hg.TransformationMat4(hg.NewVec3WithXYZ(0, 1.5, -5), hg.Deg3(5, 0, 0)) + cam := hg.CreateCamera(scene, cam_mat, 0.01, 1000) + scene.SetCurrentCamera(cam) + view_matrix := hg.InverseFast(cam_mat) + c := cam.GetCamera() + projection_matrix := hg.ComputePerspectiveProjectionMatrix(c.GetZNear(), c.GetZFar(), hg.FovToZoomFactor(c.GetFov()), hg.NewVec2WithXY(float32(res_x)/float32(res_y), 1)) + + hg.CreatePointLight(scene, hg.TranslationMat4(hg.NewVec3WithXYZ(3, 4, -6)), 0) + + cube_node := hg.CreatePhysicCubeWithSliceOfMaterialsMass(scene, hg.NewVec3WithXYZ(1, 1, 1), hg.TranslationMat4(hg.NewVec3WithXYZ(1.25, 2.5, 0)), cube_ref, hg.GoSliceOfMaterial{mat}, 2) + hg.CreatePhysicCubeWithSliceOfMaterialsMass(scene, hg.NewVec3WithXYZ(100, 0.02, 100), hg.TranslationMat4(hg.NewVec3WithXYZ(0, -0.005, 0)), ground_ref, hg.GoSliceOfMaterial{mat}, 0) + + clocks := hg.NewSceneClocks() + + // scene physics + physics := hg.NewSceneBullet3Physics() + physics.SceneCreatePhysicsFromAssets(scene) + + // main loop + mouse, keyboard := hg.NewMouse(), hg.NewKeyboard() + + for !hg.ReadKeyboard().Key(hg.KEscape) && hg.IsWindowOpen(win) { + keyboard.Update() + mouse.Update() + dt := hg.TickClock() + + // scene view + view_id := uint16(0) + hg.SceneUpdateSystemsWithPhysicsStepMaxPhysicsStep(scene, clocks, dt, physics, hg.TimeFromSecF(1.0/60.0), 1) + hg.SubmitSceneToPipelineWithFovAxisIsHorizontal(&view_id, scene, hg.NewIntRectWithSxSyExEy(0, 0, res_x, res_y), true, pipeline, res) + + // Debug physics display + hg.SetViewClearWithColDepthStencil(view_id, 0, hg.ColorGetBlack(), 1.0, 0) + hg.SetViewRect(view_id, 0, 0, uint16(res_x), uint16(res_y)) + hg.SetViewTransform(view_id, view_matrix, projection_matrix) + rs := hg.ComputeRenderStateWithDepthTestCulling(hg.BMOpaque, hg.DTDisabled, hg.FCDisabled) + physics.RenderCollision(view_id, vtx_line_layout, line_shader, rs, 0) + + // ImGui view + hg.ImGuiBeginFrame(res_x, res_y, dt, mouse.GetState(), keyboard.GetState()) + + imguiOpen := true + if hg.ImGuiBeginWithOpenFlags("Transform and Physics", &imguiOpen, hg.ImGuiWindowFlagsAlwaysAutoResize) { + hg.ImGuiTextWrapped("This tutorial demonstrates the interaction between the physics system and the Transform component of a node. The node position, rotation and scale are overriden by an active node rigid body.") + + hg.ImGuiSeparator() + v := cube_node.GetTransform().GetPos() + r := hg.ImGuiInputVec3WithDecimalPrecision("Transform.pos", v, 2) + if r { + cube_node.GetTransform().SetPos(v) + } + + if hg.ImGuiButton("Press to reset position using Transform.SetPos") { + cube_node.GetTransform().SetPos(hg.NewVec3WithXYZ(1.25, 2.5, 0)) + } + + hg.ImGuiSeparator() + + hg.ImGuiInputVec3WithDecimalPrecisionFlags("Transform.GetWorld().T", hg.GetT(cube_node.GetTransform().GetWorld()), 2, hg.ImGuiInputTextFlagsReadOnly) + + if physics.NodeHasBody(cube_node) { + if hg.ImGuiButton("Press to destroy the cube node physics") { + physics.NodeDestroyPhysics(cube_node) + physics.GarbageCollect(scene) + } + } else { + if hg.ImGuiButton("Create to create the cube node physics") { + physics.NodeCreatePhysicsFromAssets(cube_node) + } + } + } + + hg.ImGuiEnd() + + hg.ImGuiEndFrameWithViewId(255) + + hg.Frame() + hg.UpdateWindow(win) + } + hg.RenderShutdown() + hg.DestroyWindow(win) + + hg.WindowSystemShutdown() + hg.InputShutdown() +} diff --git a/physics_overrides_matrix.lua b/physics_overrides_matrix.lua index ac76b44..bcb2d5b 100644 --- a/physics_overrides_matrix.lua +++ b/physics_overrides_matrix.lua @@ -14,12 +14,16 @@ res = hg.PipelineResources() hg.ImGuiInit(10, hg.LoadProgramFromFile('resources_compiled/core/shader/imgui'), hg.LoadProgramFromFile('resources_compiled/core/shader/imgui_image')) +-- physics debug +vtx_line_layout = hg.VertexLayoutPosFloatColorUInt8() +line_shader = hg.LoadProgramFromFile("resources_compiled/shaders/pos_rgb") + -- create models vtx_layout = hg.VertexLayoutPosFloatNormUInt8() -cube_mdl = hg.CreateCubeModel(vtx_layout, 0.5, 0.5, 0.5) +cube_mdl = hg.CreateCubeModel(vtx_layout, 1, 1, 1) cube_ref = res:AddModel('cube', cube_mdl) -ground_mdl = hg.CreateCubeModel(vtx_layout, 50, 0.01, 50) +ground_mdl = hg.CreateCubeModel(vtx_layout, 100, 0.02, 100) ground_ref = res:AddModel('ground', ground_mdl) prg_ref = hg.LoadPipelineProgramRefFromFile('resources_compiled/core/shader/default.hps', res, hg.GetForwardPipelineInfo()) @@ -30,8 +34,12 @@ mat = hg.CreateMaterial(prg_ref, 'uDiffuseColor', hg.Vec4(0.5, 0.5, 0.5), 'uSpec -- setup scene scene = hg.Scene() -cam = hg.CreateCamera(scene, hg.TransformationMat4(hg.Vec3(0, 1.5, -5), hg.Deg3(5, 0, 0)), 0.01, 1000) +cam_mat = hg.TransformationMat4(hg.Vec3(0, 1.5, -5), hg.Deg3(5, 0, 0)) +cam = hg.CreateCamera(scene, cam_mat, 0.01, 1000) scene:SetCurrentCamera(cam) +view_matrix = hg.InverseFast(cam_mat) +c = cam:GetCamera() +projection_matrix = hg.ComputePerspectiveProjectionMatrix(c:GetZNear(), c:GetZFar(), hg.FovToZoomFactor(c:GetFov()), hg.Vec2(res_x / res_y, 1)) lgt = hg.CreatePointLight(scene, hg.TranslationMat4(hg.Vec3(3, 4, -6)), 0) @@ -50,9 +58,21 @@ mouse, keyboard = hg.Mouse(), hg.Keyboard() while not keyboard:Pressed(hg.K_Escape) and hg.IsWindowOpen(win) do keyboard:Update() mouse:Update() + dt = hg.TickClock() + + -- scene view + view_id = 0 + hg.SceneUpdateSystems(scene, clocks, dt, physics, hg.time_from_sec_f(1 / 60), 1) + view_id,_ = hg.SubmitSceneToPipeline(view_id, scene, hg.IntRect(0, 0, res_x, res_y), true, pipeline, res) + + -- Debug physics display + hg.SetViewClear(view_id, 0, 0, 1.0, 0) + hg.SetViewRect(view_id, 0, 0, res_x, res_y) + hg.SetViewTransform(view_id, view_matrix, projection_matrix) + rs = hg.ComputeRenderState(hg.BM_Opaque, hg.DT_Disabled, hg.FC_Disabled) + physics:RenderCollision(view_id, vtx_line_layout, line_shader, rs, 0) -- ImGui view - dt = hg.TickClock() hg.ImGuiBeginFrame(res_x, res_y, dt, mouse:GetState(), keyboard:GetState()) if hg.ImGuiBegin('Transform and Physics', true, hg.ImGuiWindowFlags_AlwaysAutoResize) then @@ -89,10 +109,6 @@ while not keyboard:Pressed(hg.K_Escape) and hg.IsWindowOpen(win) do hg.ImGuiEndFrame(255) - -- scene view - hg.SceneUpdateSystems(scene, clocks, dt, physics, hg.time_from_sec_f(1 / 60), 1) - hg.SubmitSceneToPipeline(0, scene, hg.IntRect(0, 0, res_x, res_y), true, pipeline, res) - hg.Frame() hg.UpdateWindow(win) end diff --git a/physics_overrides_matrix.py b/physics_overrides_matrix.py index 74c0930..a20cb0e 100644 --- a/physics_overrides_matrix.py +++ b/physics_overrides_matrix.py @@ -14,12 +14,16 @@ hg.ImGuiInit(10, hg.LoadProgramFromFile('resources_compiled/core/shader/imgui'), hg.LoadProgramFromFile('resources_compiled/core/shader/imgui_image')) +# physics debug +vtx_line_layout = hg.VertexLayoutPosFloatColorUInt8() +line_shader = hg.LoadProgramFromFile("resources_compiled/shaders/pos_rgb") + # create models vtx_layout = hg.VertexLayoutPosFloatNormUInt8() -cube_mdl = hg.CreateCubeModel(vtx_layout, 0.5, 0.5, 0.5) +cube_mdl = hg.CreateCubeModel(vtx_layout, 1, 1, 1) cube_ref = res.AddModel('cube', cube_mdl) -ground_mdl = hg.CreateCubeModel(vtx_layout, 50, 0.01, 50) +ground_mdl = hg.CreateCubeModel(vtx_layout, 100, 0.02, 100) ground_ref = res.AddModel('ground', ground_mdl) prg_ref = hg.LoadPipelineProgramRefFromFile('resources_compiled/core/shader/default.hps', res, hg.GetForwardPipelineInfo()) @@ -30,8 +34,13 @@ # setup scene scene = hg.Scene() -cam = hg.CreateCamera(scene, hg.TransformationMat4(hg.Vec3(0, 1.5, -5), hg.Deg3(5, 0, 0)), 0.01, 1000) +cam_mat = hg.TransformationMat4(hg.Vec3(0, 1.5, -5), hg.Deg3(5, 0, 0)) +cam = hg.CreateCamera(scene, cam_mat, 0.01, 1000) scene.SetCurrentCamera(cam) +view_matrix = hg.InverseFast(cam_mat) +c = cam.GetCamera() +projection_matrix = hg.ComputePerspectiveProjectionMatrix(c.GetZNear(), c.GetZFar(), hg.FovToZoomFactor(c.GetFov()), hg.Vec2(res_x / res_y, 1)) + lgt = hg.CreatePointLight(scene, hg.TranslationMat4(hg.Vec3(3, 4, -6)), 0) @@ -50,9 +59,21 @@ while not keyboard.Pressed(hg.K_Escape) and hg.IsWindowOpen(win): keyboard.Update() mouse.Update() + dt = hg.TickClock() + + # scene view + view_id = 0 + hg.SceneUpdateSystems(scene, clocks, dt, physics, hg.time_from_sec_f(1 / 60), 1) + view_id, _ = hg.SubmitSceneToPipeline(view_id, scene, hg.IntRect(0, 0, res_x, res_y), True, pipeline, res) + + # Debug physics display + hg.SetViewClear(view_id, 0, 0, 1.0, 0) + hg.SetViewRect(view_id, 0, 0, res_x, res_y) + hg.SetViewTransform(view_id, view_matrix, projection_matrix) + rs = hg.ComputeRenderState(hg.BM_Opaque, hg.DT_Disabled, hg.FC_Disabled) + physics.RenderCollision(view_id, vtx_line_layout, line_shader, rs, 0) # ImGui view - dt = hg.TickClock() hg.ImGuiBeginFrame(res_x, res_y, dt, mouse.GetState(), keyboard.GetState()) if hg.ImGuiBegin('Transform and Physics', True, hg.ImGuiWindowFlags_AlwaysAutoResize): @@ -83,10 +104,6 @@ hg.ImGuiEndFrame(255) - # scene view - hg.SceneUpdateSystems(scene, clocks, dt, physics, hg.time_from_sec_f(1 / 60), 1) - hg.SubmitSceneToPipeline(0, scene, hg.IntRect(0, 0, res_x, res_y), True, pipeline, res) - hg.Frame() hg.UpdateWindow(win) diff --git a/physics_pool_of_objects.go b/physics_pool_of_objects.go new file mode 100644 index 0000000..dfa9531 --- /dev/null +++ b/physics_pool_of_objects.go @@ -0,0 +1,139 @@ +package main + +import ( + "fmt" + + hg "github.com/harfang3d/harfang-go/v3" +) + +var prg_ref *hg.PipelineProgramRef + +func create_material(diffuse *hg.Vec4, specular *hg.Vec4, self *hg.Vec4) *hg.Material { + mat := hg.CreateMaterialWithValueName0Value0ValueName1Value1(prg_ref, "uDiffuseColor", diffuse, "uSpecularColor", specular) + hg.SetMaterialValueWithVec4V(mat, "uSelfColor", self) + return mat +} + +func main() { + hg.InputInit() + hg.WindowSystemInit() + + res_x, res_y := int32(1280), int32(720) + win := hg.RenderInitWithWindowTitleWidthHeightResetFlags("Harfang - Physics Pool", res_x, res_y, hg.RFVSync|hg.RFMSAA4X) + + hg.AddAssetsFolder("resources_compiled") + + pipeline := hg.CreateForwardPipeline() + res := hg.NewPipelineResources() + + // create models + vtx_layout := hg.VertexLayoutPosFloatNormUInt8() + + sphere_mdl := hg.CreateSphereModel(vtx_layout, 0.5, 12, 24) + sphere_ref := res.AddModel("sphere", sphere_mdl) + cube_mdl := hg.CreateCubeModel(vtx_layout, 1, 1, 1) + cube_ref := res.AddModel("cube", cube_mdl) + + // create materials + prg_ref = hg.LoadPipelineProgramRefFromAssets("core/shader/default.hps", res, hg.GetForwardPipelineInfo()) + + mat_ground := create_material(hg.NewVec4WithXYZ(0.5, 0.5, 0.5), hg.NewVec4WithXYZ(0.1, 0.1, 0.1), hg.NewVec4WithXYZ(0, 0, 0)) + mat_walls := create_material(hg.NewVec4WithXYZ(0.5, 0.5, 0.5), hg.NewVec4WithXYZ(0.1, 0.1, 0.1), hg.NewVec4WithXYZ(0, 0, 0)) + mat_objects := create_material(hg.NewVec4WithXYZ(0.5, 0.5, 0.5), hg.NewVec4WithXYZ(1, 1, 1), hg.NewVec4WithXYZ(0, 0, 0)) + + // setup scene + scene := hg.NewScene() + scene.GetCanvas().SetColor(hg.ColorI(22, 56, 76)) + scene.GetEnvironment().SetFogColor(scene.GetCanvas().GetColor()) + scene.GetEnvironment().SetFogNear(20) + scene.GetEnvironment().SetFogFar(80) + + cam_mtx := hg.TransformationMat4(hg.NewVec3WithXYZ(0, 20, -30), hg.Deg3(30, 0, 0)) + cam := hg.CreateCamera(scene, cam_mtx, 0.01, 5000) + scene.SetCurrentCamera(cam) + + hg.CreateLinearLightWithDiffuseSpecularPriorityShadowTypeShadowBiasPssmSplit(scene, hg.TransformationMat4(hg.NewVec3WithXYZ(0, 0, 0), hg.Deg3(30, 59, 0)), hg.NewColorWithRGB(1, 0.8, 0.7), hg.NewColorWithRGB(1, 0.8, 0.7), 10, hg.LSTMap, 0.002, hg.NewVec4WithXYZW(50, 100, 200, 400)) + hg.CreatePointLightWithDiffuseSpecular(scene, hg.TranslationMat4(hg.NewVec3WithXYZ(0, 10, 10)), 100, hg.ColorI(94, 155, 228), hg.ColorI(94, 255, 228)) + + mdl_ref := res.AddModel("ground", hg.CreateCubeModel(vtx_layout, 100, 1, 100)) + hg.CreatePhysicCubeWithSliceOfMaterialsMass(scene, hg.NewVec3WithXYZ(30, 1, 30), hg.TranslationMat4(hg.NewVec3WithXYZ(0, -0.5, 0)), mdl_ref, hg.GoSliceOfMaterial{mat_ground}, 0) + mdl_ref = res.AddModel("wall", hg.CreateCubeModel(vtx_layout, 1, 11, 32)) + hg.CreatePhysicCubeWithSliceOfMaterialsMass(scene, hg.NewVec3WithXYZ(1, 11, 32), hg.TranslationMat4(hg.NewVec3WithXYZ(-15.5, -0.5, 0)), mdl_ref, hg.GoSliceOfMaterial{mat_walls}, 0) + hg.CreatePhysicCubeWithSliceOfMaterialsMass(scene, hg.NewVec3WithXYZ(1, 11, 32), hg.TranslationMat4(hg.NewVec3WithXYZ(15.5, -0.5, 0)), mdl_ref, hg.GoSliceOfMaterial{mat_walls}, 0) + mdl_ref = res.AddModel("wall2", hg.CreateCubeModel(vtx_layout, 32, 11, 1)) + hg.CreatePhysicCubeWithSliceOfMaterialsMass(scene, hg.NewVec3WithXYZ(32, 11, 1), hg.TranslationMat4(hg.NewVec3WithXYZ(0, -0.5, -15.5)), mdl_ref, hg.GoSliceOfMaterial{mat_walls}, 0) + hg.CreatePhysicCubeWithSliceOfMaterialsMass(scene, hg.NewVec3WithXYZ(32, 11, 1), hg.TranslationMat4(hg.NewVec3WithXYZ(0, -0.5, 15.5)), mdl_ref, hg.GoSliceOfMaterial{mat_walls}, 0) + + clocks := hg.NewSceneClocks() + + // setup physics + physics := hg.NewSceneBullet3Physics() + physics.SceneCreatePhysicsFromAssets(scene) + + physic_nodes := []*hg.Node{} // keep track of dynamically created physic nodes + + // text rendering + font := hg.LoadFontFromAssetsWithSize("font/default.ttf", 32) + font_program := hg.LoadProgramFromAssetsWithVertexShaderNameFragmentShaderName("core/shader/font.vsb", "core/shader/font.fsb") + + text_uniform_values := hg.GoSliceOfUniformSetValue{hg.MakeUniformSetValueWithVec4V("u_color", hg.NewVec4WithXYZ(1, 1, 0.5))} + text_render_state := hg.ComputeRenderStateWithDepthTestCulling(hg.BMAlpha, hg.DTAlways, hg.FCDisabled) + + // main loop + for hg.IsWindowOpen(win) { + + state := hg.ReadKeyboard() + + if state.Key(hg.KS) { + for i := 1; i < 8; i += 1 { + hg.SetMaterialValueWithVec4V(mat_objects, "uDiffuseColor", hg.RandomVec4(0, 1)) + + var node *hg.Node + if hg.FRand() > 0.5 { + node = hg.CreatePhysicCubeWithSliceOfMaterialsMass(scene, hg.Vec3GetOne(), hg.TranslationMat4(hg.RandomVec3WithMinMax(hg.NewVec3WithXYZ(-10, 18, -10), hg.NewVec3WithXYZ(10, 18, 10))), cube_ref, hg.GoSliceOfMaterial{mat_objects}, 1) + } else { + node = hg.CreatePhysicSphereWithSliceOfMaterialsMass(scene, 0.5, hg.TranslationMat4(hg.RandomVec3WithMinMax(hg.NewVec3WithXYZ(-10, 18, -10), hg.NewVec3WithXYZ(10, 18, 10))), sphere_ref, hg.GoSliceOfMaterial{mat_objects}, 1) + } + physics.NodeCreatePhysicsFromAssets(node) // update physics state + + physic_nodes = append(physic_nodes, node) + } + } else if state.Key(hg.KD) { + if len(physic_nodes) > 0 { + for i := 1; i < 8; i += 1 { + node := physic_nodes[0] + + if node != nil { + scene.DestroyNode(node) + physic_nodes = physic_nodes[1:] + } + } + } + + hg.SceneGarbageCollectSystemsWithPhysics(scene, physics) + } else if state.Key(hg.KEscape) { + break + } + + // update scene and physic system, synchronize physics to scene, submit scene to draw + dt := hg.TickClock() + + hg.SceneUpdateSystemsWithPhysicsStepMaxPhysicsStep(scene, clocks, dt, physics, hg.TimeFromSecF(1.0/60.0), 4) + view_id := uint16(0) + hg.SubmitSceneToPipelineWithFovAxisIsHorizontal(&view_id, scene, hg.NewIntRectWithSxSyExEy(0, 0, res_x, res_y), true, pipeline, res) + + // on-screen usage text + hg.SetView2DWithZnearZfarFlagsColorDepthStencil(view_id, 0, 0, res_x, res_y, -1, 1, hg.CFDepth, hg.ColorGetBlack(), 1, 0) + hg.DrawTextWithPosHalignValignSliceOfValuesSliceOfTexturesState(view_id, font, "S: Add object - D: Destruct object", font_program, "u_tex", 0, hg.Mat4GetIdentity(), hg.NewVec3WithXYZ(460, float32(res_y-60), 0), hg.DTHALeft, hg.DTVABottom, text_uniform_values, hg.GoSliceOfUniformSetTexture{}, text_render_state) + hg.DrawTextWithPosHalignValignSliceOfValuesSliceOfTexturesState(view_id, font, fmt.Sprint("%d Object", len(physic_nodes)), font_program, "u_tex", 0, hg.Mat4GetIdentity(), hg.NewVec3WithXYZ(float32(res_x-200), float32(res_y-60), 0), hg.DTHALeft, hg.DTVABottom, text_uniform_values, hg.GoSliceOfUniformSetTexture{}, text_render_state) + + hg.Frame() + hg.UpdateWindow(win) + } + + hg.RenderShutdown() + hg.DestroyWindow(win) + + hg.WindowSystemShutdown() + hg.InputShutdown() +} diff --git a/picture_load.go b/picture_load.go new file mode 100644 index 0000000..4493c01 --- /dev/null +++ b/picture_load.go @@ -0,0 +1,17 @@ +package main + +import ( + "fmt" + + hg "github.com/harfang3d/harfang-go/v3" +) + +func main() { + pic := hg.NewPicture() + + if hg.LoadPicture(pic, "resources/pictures/owl.jpg") { + fmt.Printf("Picture dimensions: %dx%d", pic.GetWidth(), pic.GetHeight()) + } else { + fmt.Println("Failed to load picture!") + } +} diff --git a/picture_save.go b/picture_save.go new file mode 100644 index 0000000..38d5bb1 --- /dev/null +++ b/picture_save.go @@ -0,0 +1,19 @@ +package main + +import ( + hg "github.com/harfang3d/harfang-go/v3" +) + +func main() { + pic := hg.NewPicture() + + if !hg.LoadJPG(pic, "resources/pictures/owl.jpg") { + panic("Failed to load picture!") + } + + if !hg.SavePNG(pic, "owl.png") { + panic("Failed to save picture!") + } + + print("Conversion complete") +} diff --git a/render_resize_to_window.go b/render_resize_to_window.go new file mode 100644 index 0000000..6975edb --- /dev/null +++ b/render_resize_to_window.go @@ -0,0 +1,39 @@ +package main + +import ( + "fmt" + + hg "github.com/harfang3d/harfang-go/v3" +) + +func main() { + hg.InputInit() + hg.WindowSystemInit() + + res_x, res_y := int32(512), int32(512) + win := hg.RenderInitWithWindowTitleWidthHeightResetFlags("Harfang - Render Resize to Window", res_x, res_y, hg.RFVSync|hg.RFMSAA4X) + + // create model + vtx_layout := hg.VertexLayoutPosFloatNormUInt8() + + cube_mdl := hg.CreateCubeModel(vtx_layout, 1, 1, 1) + cube_prg := hg.LoadProgramFromFile("resources_compiled/shaders/mdl") + + // main loop + for !hg.ReadKeyboard().Key(hg.KEscape) && hg.IsWindowOpen(win) { + render_was_reset := hg.RenderResetToWindowWithResetFlags(win, &res_x, &res_y, uint32(hg.RFVSync|hg.RFMSAA4X|hg.RFMaxAnisotropy)) + if render_was_reset { + fmt.Printf("Render reset to %dx%d", res_x, res_y) + } + + viewpoint := hg.TransformationMat4(hg.NewVec3WithXYZ(1, 1, -2), hg.Deg3(24, -27, 0)) + hg.SetViewPerspectiveWithZnearZfarZoomFactorFlagsColorDepthStencil(0, 0, 0, res_x, res_y, viewpoint, 0.01, 100, 1.8, hg.CFColor|hg.CFDepth, hg.ColorI(64, 64, 64), 1, 0) + + hg.DrawModelWithSliceOfValuesSliceOfTextures(0, cube_mdl, cube_prg, hg.GoSliceOfUniformSetValue{}, hg.GoSliceOfUniformSetTexture{}, hg.TranslationMat4(hg.NewVec3WithXYZ(0, 0, 0))) + + hg.Frame() + hg.UpdateWindow(win) + } + + hg.RenderShutdown() +} diff --git a/resources/core/shader/default.hps b/resources/core/shader/default.hps index bfa49da..861f19d 100644 --- a/resources/core/shader/default.hps +++ b/resources/core/shader/default.hps @@ -1,3 +1,3 @@ { - "features": ["OptionalDiffuseMap", "OptionalSpecularMap", "OptionalNormalMap", "OptionalSelfMap", "OptionalSkinning"] + "features": ["OptionalDiffuseMap", "OptionalSkinning"] } diff --git a/resources/core/shader/font_fs.sc b/resources/core/shader/font_fs.sc index 7bfc6fa..2127b0e 100644 --- a/resources/core/shader/font_fs.sc +++ b/resources/core/shader/font_fs.sc @@ -7,6 +7,6 @@ uniform vec4 u_color; SAMPLER2D(u_tex, 0); void main() { - float opacity = texture2D(u_tex, v_texcoord0).a * u_color.a; - gl_FragColor = vec4(u_color.rgb, opacity); + float opacity = texture2D(u_tex, v_texcoord0).w * u_color.w; + gl_FragColor = vec4(u_color.xyz, opacity); } diff --git a/resources/core/shader/hiz_trace.sh b/resources/core/shader/hiz_trace.sh index cf8aeb6..3851d35 100644 --- a/resources/core/shader/hiz_trace.sh +++ b/resources/core/shader/hiz_trace.sh @@ -8,27 +8,27 @@ uniform vec4 u_depthTexInfos; // width(x) heigh(y) start mipmap level(z) max mip // vec3 ray_step_cell(vec3 ray, vec3 dir, float step, vec2 z_range) { - float t_ = 100000000.0; // [EJ] any large value is ok + float t = 100000000.0; // [EJ] any large value is ok if (dir.x > 0.0) - t_ = min(t_, (floor(ray.x / step + 1.0) * step - ray.x) / dir.x); + t = min(t, (floor(ray.x / step + 1.0) * step - ray.x) / dir.x); else if (dir.x < 0.0) - t_ = min(t_, (ceil(ray.x / step - 1.0) * step - ray.x) / dir.x); + t = min(t, (ceil(ray.x / step - 1.0) * step - ray.x) / dir.x); if (dir.y > 0.0) - t_ = min(t_, (floor(ray.y / step + 1.0) * step - ray.y) / dir.y); + t = min(t, (floor(ray.y / step + 1.0) * step - ray.y) / dir.y); else if (dir.y < 0.0) - t_ = min(t_, (ceil(ray.y / step - 1.0) * step - ray.y) / dir.y); + t = min(t, (ceil(ray.y / step - 1.0) * step - ray.y) / dir.y); if (dir.z > 0.0) { if (ray.z < z_range.x) - t_ = min(t_, (z_range.x - ray.z) / dir.z); + t = min(t, (z_range.x - ray.z) / dir.z); } else if (dir.z < 0.0) { if (ray.z > z_range.y) - t_ = min(t_, (z_range.y - ray.z) / dir.z); + t = min(t, (z_range.y - ray.z) / dir.z); } - return ray + dir * t_; + return ray + dir * t; } float hiz_trace(vec3 ray_o, vec3 ray_d, mat4 proj, float z_near, int max_iterations, out vec3 ray) { @@ -87,8 +87,8 @@ float hiz_trace(vec3 ray_o, vec3 ray_d, mat4 proj, float z_near, int max_iterati } } - vec2 k_fade = saturate((ray.xy - viewport_min) / (u_viewRect.zw * 0.1)); - k_fade *= saturate(vec2(1.0, 1.0) - (ray.xy - viewport_max * 0.9) / (u_viewRect.zw * 0.1)); + vec2 k_fade = saturate((ray.xy - viewport_min.xy) / (u_viewRect.zw * 0.1)); + k_fade *= saturate(vec2(1.0, 1.0) - (ray.xy - viewport_max.xy * 0.9) / (u_viewRect.zw * 0.1)); ray.xy /= u_depthTexInfos.xy; diff --git a/resources/core/shader/pbr_fs.sc b/resources/core/shader/pbr_fs.sc index 69ba38b..3e24b81 100644 --- a/resources/core/shader/pbr_fs.sc +++ b/resources/core/shader/pbr_fs.sc @@ -38,15 +38,15 @@ float SampleShadowPCF(sampler2DShadow map, vec4 coord, float inv_pixel_size, flo float k = 0.0; #if FORWARD_PIPELINE_AAA - #define PCF_SAMPLE_COUNT 2.0 // 3x3 + #define PCF_SAMPLE_COUNT 2 // 3x3 -// float weights[9] = {0.024879, 0.107973, 0.024879, 0.107973, 0.468592, 0.107973, 0.024879, 0.107973, 0.024879}; - float weights[9] = {0.011147, 0.083286, 0.011147, 0.083286, 0.622269, 0.083286, 0.011147, 0.083286, 0.011147}; +// ARRAY_BEGIN(float, weights, 9) 0.024879, 0.107973, 0.024879, 0.107973, 0.468592, 0.107973, 0.024879, 0.107973, 0.024879 ARRAY_END(); + ARRAY_BEGIN(float, weights, 9) 0.011147, 0.083286, 0.011147, 0.083286, 0.622269, 0.083286, 0.011147, 0.083286, 0.011147 ARRAY_END(); - for (float j = 0.0; j <= PCF_SAMPLE_COUNT; ++j) { - float v = 6.0 * (j + jitter.y) / PCF_SAMPLE_COUNT - 1.0; - for (float i = 0.0; i <= PCF_SAMPLE_COUNT; ++i) { - float u = 6.0 * (i + jitter.x) / PCF_SAMPLE_COUNT - 1.0; + for (int j = 0; j <= PCF_SAMPLE_COUNT; ++j) { + float v = 6.0 * (float(j) + jitter.y) / float(PCF_SAMPLE_COUNT) - 1.0; + for (int i = 0; i <= PCF_SAMPLE_COUNT; ++i) { + float u = 6.0 * (float(i) + jitter.x) / float(PCF_SAMPLE_COUNT) - 1.0; k += SampleHardShadow(map, coord + vec4(vec2(u, v) * k_pixel_size, 0.0, 0.0), bias) * weights[j * 3 + i]; } } @@ -247,7 +247,7 @@ void main() { vec4 ss_radiance = texture2D(uSSRadianceMap, gl_FragCoord.xy / uResolution.xy); irradiance = ss_irradiance.xyz; // mix(irradiance, ss_irradiance, ss_irradiance.w); - radiance = mix(radiance, ss_radiance, ss_radiance.w); + radiance = mix(radiance, ss_radiance.xyz, ss_radiance.w); #endif vec3 diffuse = irradiance * base_opacity.xyz; diff --git a/resources/core/shader/ssgi_fs.sc b/resources/core/shader/ssgi_fs.sc index efd98fa..42156ea 100644 --- a/resources/core/shader/ssgi_fs.sc +++ b/resources/core/shader/ssgi_fs.sc @@ -22,11 +22,11 @@ void main() { vec4 jitter = texture2D(u_noise, mod(gl_FragCoord.xy, vec2(64, 64)) / vec2(64, 64)); // sample normal/depth - vec2 uv = GetAttributeTexCoord(vTexCoord0, textureSize(u_attr0, 0).xy); + vec2 uv = GetAttributeTexCoord(vTexCoord0, vec2(textureSize(u_attr0, 0).xy)); vec4 attr0 = texture2D(u_attr0, uv); vec3 n = normalize(attr0.xyz); - if (isNan(n.x) || isNan(n.y) |isNan(n.z)) + if (isNan(n.x) || isNan(n.y) || isNan(n.z)) n = vec3(0, 1, 0); // compute ray origin & direction @@ -45,7 +45,7 @@ void main() { float cos_spread = cos(spread), sin_spread = sin(spread); for (int j = 0; j < int(sample_count); ++j) { - float angle = float(j + jitter.w) / sample_count * 2. * 3.141592; + float angle = (float(j) + jitter.w) / sample_count * 2.0 * 3.141592; float cos_angle = cos(angle), sin_angle = sin(angle); vec3 ray_d_spread = (right * cos_angle + up * sin_angle) * sin_spread + n * cos_spread; diff --git a/resources/core/shader/ssr_fs.sc b/resources/core/shader/ssr_fs.sc index 9207050..b7174c0 100644 --- a/resources/core/shader/ssr_fs.sc +++ b/resources/core/shader/ssr_fs.sc @@ -22,11 +22,11 @@ void main() { vec4 jitter = texture2D(u_noise, mod(gl_FragCoord.xy, vec2(64, 64)) / vec2(64, 64)); // sample normal/depth - vec2 uv = GetAttributeTexCoord(vTexCoord0, textureSize(u_attr0, 0).xy); + vec2 uv = GetAttributeTexCoord(vTexCoord0, vec2(textureSize(u_attr0, 0).xy)); vec4 attr0 = texture2D(u_attr0, uv); vec3 n = normalize(attr0.xyz); - if (isNan(n.x) || isNan(n.y) |isNan(n.z)) + if (isNan(n.x) || isNan(n.y) || isNan(n.z)) n = vec3(0, 1, 0); // compute ray origin & direction @@ -66,7 +66,7 @@ void main() { float cos_spread = cos(spread), sin_spread = sin(spread); for (int j = 0; j < int(sample_count); ++j) { - float angle = float(j + jitter.w) / sample_count * 2. * 3.141592; + float angle = (float(j) + jitter.w) / sample_count * 2.0 * 3.141592; vec3 ray_d_spread = (right * cos(angle) + up * sin(angle)) * sin_spread + ray_d * cos_spread; vec3 world_ray_d = mul(uMainInvView, vec4(ray_d_spread, 0.0)).xyz; @@ -85,11 +85,11 @@ void main() { float log_depth = ComputeRayLogDepth(uMainProjection, hit_point); - vec4 output = vec4(0.0, 0.0, 0.0, 1.0); // assume backface hit + vec4 ss_output = vec4(0.0, 0.0, 0.0, 1.0); // assume backface hit if (dot(attr0.xyz, ray_d_spread) < 0.0 && hit_point.z <= log_depth) - output = vec4(texture2D(u_color, uv - vel * uv_ratio).xyz, 1.0); // front face hit + ss_output = vec4(texture2D(u_color, uv - vel * uv_ratio).xyz, 1.0); // front face hit - color += mix(fallback, output, k); + color += mix(fallback, ss_output, k); } else { color += fallback; } @@ -97,6 +97,7 @@ void main() { } color /= sample_count * sample_count; + color = clamp(color, 0.0, 32.0); // [FG] Avoid high intensity HDR probes from saturating the SSR buffer. #endif gl_FragColor = color; diff --git a/resources/core/shader/temporal_accumulation_fs.sc b/resources/core/shader/temporal_accumulation_fs.sc index d8a3eb1..46f7045 100644 --- a/resources/core/shader/temporal_accumulation_fs.sc +++ b/resources/core/shader/temporal_accumulation_fs.sc @@ -25,7 +25,7 @@ void main() { vec2 uv = gl_FragCoord.xy / input_size; vec2 dt = GetVelocityVector(uv, uResolution.xy / input_size.xy); - vec2 uv_curr = GetAttributeTexCoord(vTexCoord0, textureSize(u_current, 0).xy); + vec2 uv_curr = GetAttributeTexCoord(vTexCoord0, vec2(textureSize(u_current, 0).xy)); vec4 current = texture2D(u_current, uv_curr); vec4 c0 = texture2DLodOffset(u_current, uv_curr, 0, ivec2(0, 1)); diff --git a/scene_aaa.go b/scene_aaa.go new file mode 100644 index 0000000..206a80f --- /dev/null +++ b/scene_aaa.go @@ -0,0 +1,49 @@ +// Toyota 2JZ-GTE Engine model by Serhii Denysenko (CGTrader: serhiidenysenko8256) +// URL : https://www.cgtrader.com/3d-models/vehicle/part/toyota-2jz-gte-engine-2932b715-2f42-4ecd-93ce-df9507c67ce8 +package main + +import ( + hg "github.com/harfang3d/harfang-go/v3" +) + +func main() { + hg.InputInit() + hg.WindowSystemInit() + + res_x, res_y := int32(1280), int32(720) + win := hg.RenderInitWithWindowTitleWidthHeightResetFlags("AAA Scene", res_x, res_y, hg.RFVSync|hg.RFMSAA4X) + + pipeline := hg.CreateForwardPipeline() + res := hg.NewPipelineResources() + + hg.AddAssetsFolder("resources_compiled") + + // load scene + scene := hg.NewScene() + hg.LoadSceneFromAssets("car_engine/engine.scn", scene, res, hg.GetForwardPipelineInfo()) + + // AAA pipeline + pipeline_aaa_config := hg.NewForwardPipelineAAAConfig() + pipeline_aaa := hg.CreateForwardPipelineAAAFromAssetsWithSsgiRatioSsrRatio("core", pipeline_aaa_config, hg.BREqual, hg.BREqual) + pipeline_aaa_config.SetSampleCount(1) + + // main loop + frame := int32(0) + for !hg.ReadKeyboard().Key(hg.KEscape) && hg.IsWindowOpen(win) { + + dt := hg.TickClock() + + trs := scene.GetNode("engine_master").GetTransform() + trs.SetRot(trs.GetRot().Add(hg.NewVec3WithXYZ(0, hg.Deg(15)*hg.TimeToSecF(dt), 0))) + + scene.Update(dt) + viewId := uint16(0) + hg.SubmitSceneToPipelineWithFovAxisIsHorizontalAaaAaaConfigFrame(&viewId, scene, hg.NewIntRectWithSxSyExEy(0, 0, res_x, res_y), true, pipeline, res, pipeline_aaa, pipeline_aaa_config, frame) + + frame = int32(hg.Frame()) + hg.UpdateWindow(win) + } + + hg.RenderShutdown() + hg.DestroyWindow(win) +} diff --git a/scene_draw_to_multiple_viewports.go b/scene_draw_to_multiple_viewports.go new file mode 100644 index 0000000..e359c94 --- /dev/null +++ b/scene_draw_to_multiple_viewports.go @@ -0,0 +1,86 @@ +package main + +import ( + hg "github.com/harfang3d/harfang-go/v3" +) + +func main() { + hg.InputInit() + hg.WindowSystemInit() + + res_x, res_y := int32(1280), int32(720) + win := hg.RenderInitWithWindowTitleWidthHeightResetFlags("Harfang - Scene Draw to Multiple Viewports", res_x, res_y, hg.RFVSync|hg.RFMSAA4X) + + hg.AddAssetsFolder("resources_compiled") + + pipeline := hg.CreateForwardPipeline() + res := hg.NewPipelineResources() + + // create models + vtx_layout := hg.VertexLayoutPosFloatNormUInt8() + + cube_mdl := hg.CreateCubeModel(vtx_layout, 1, 1, 1) + cube_ref := res.AddModel("cube", cube_mdl) + ground_mdl := hg.CreateCubeModel(vtx_layout, 100, 0.01, 100) + ground_ref := res.AddModel("ground", ground_mdl) + + // create materials + shader := hg.LoadPipelineProgramRefFromAssets("core/shader/default.hps", res, hg.GetForwardPipelineInfo()) + + mat_yellow_cube := hg.CreateMaterialWithValueName0Value0ValueName1Value1(shader, "uDiffuseColor", hg.Vec4I(255, 220, 64), "uSpecularColor", hg.Vec4I(255, 220, 64)) + mat_red_cube := hg.CreateMaterialWithValueName0Value0ValueName1Value1(shader, "uDiffuseColor", hg.Vec4I(255, 0, 0), "uSpecularColor", hg.Vec4I(255, 0, 0)) + mat_ground := hg.CreateMaterialWithValueName0Value0ValueName1Value1(shader, "uDiffuseColor", hg.Vec4I(128, 128, 128), "uSpecularColor", hg.Vec4I(128, 128, 128)) + + // setup scene (note that we do not create any camera) + scene := hg.NewScene() + + hg.CreateSpotLightWithDiffuseSpecularPriorityShadowTypeShadowBias(scene, hg.TransformationMat4(hg.NewVec3WithXYZ(-8, 4, -5), hg.Deg3(19, 59, 0)), 0, hg.Deg(5), hg.Deg(30), hg.ColorGetWhite(), hg.ColorGetWhite(), 10, hg.LSTMap, 0.00005) + hg.CreatePointLightWithDiffuseSpecularPriority(scene, hg.TranslationMat4(hg.NewVec3WithXYZ(3, 1, 2.5)), 5, hg.ColorI(128, 192, 255), hg.ColorGetBlack(), 0) + + yellow_cube := hg.CreateObjectWithSliceOfMaterials(scene, hg.TransformationMat4(hg.NewVec3WithXYZ(1, 0.5, 0), hg.NewVec3WithXYZ(0, hg.Deg(0), 0)), cube_ref, hg.GoSliceOfMaterial{mat_yellow_cube}) + hg.CreateObjectWithSliceOfMaterials(scene, hg.TranslationMat4(hg.NewVec3WithXYZ(-1, 0.5, 0)), cube_ref, hg.GoSliceOfMaterial{mat_red_cube}) + hg.CreateObjectWithSliceOfMaterials(scene, hg.TranslationMat4(hg.NewVec3WithXYZ(0, 0, 0)), ground_ref, hg.GoSliceOfMaterial{mat_ground}) + + // define viewports + viewports := []struct { + rect *hg.IntRect + cam_pos, cam_rot *hg.Vec3 + }{ + {rect: hg.NewIntRectWithSxSyExEy(0, 0, res_x/2, res_y/2), cam_pos: hg.NewVec3WithXYZ(-4.015, 2.368, -3.484), cam_rot: hg.NewVec3WithXYZ(0.35, 0.87, 0.0)}, + {rect: hg.NewIntRectWithSxSyExEy(res_x/2, 0, res_x, res_y/2), cam_pos: hg.NewVec3WithXYZ(-4.143, 2.976, 4.127), cam_rot: hg.NewVec3WithXYZ(0.423, 2.365, 0.0)}, + {rect: hg.NewIntRectWithSxSyExEy(0, res_y/2, res_x/2, res_y), cam_pos: hg.NewVec3WithXYZ(4.020, 2.374, 3.469), cam_rot: hg.NewVec3WithXYZ(0.353, 4.016, 0.0)}, + {rect: hg.NewIntRectWithSxSyExEy(res_x/2, res_y/2, res_x, res_y), cam_pos: hg.NewVec3WithXYZ(3.469, 2.374, -4.020), cam_rot: hg.NewVec3WithXYZ(0.353, -0.695, 0.0)}, + } + + // main loop + for !hg.ReadKeyboard().Key(hg.KEscape) && hg.IsWindowOpen(win) { + dt := hg.TickClock() + + // animate yellow cube & update scene once for all viewports + rot := yellow_cube.GetTransform().GetRot() + rot.SetY(rot.GetY() + hg.TimeToSecF(dt)) + yellow_cube.GetTransform().SetRot(rot) + + scene.Update(dt) + + // prepare view-independent render data (eg. spot shadow maps) + render_data := hg.NewSceneForwardPipelineRenderData() + + views := hg.NewSceneForwardPipelinePassViewId() + vid := uint16(0) + hg.PrepareSceneForwardPipelineCommonRenderData(&vid, scene, render_data, pipeline, res, views) + + for _, viewport := range viewports { + // compute viewport specific view state + view_state := hg.ComputePerspectiveViewState(hg.TransformationMat4(viewport.cam_pos, viewport.cam_rot), hg.Deg(45), 0.01, 1000, hg.ComputeAspectRatioX(float32(res_x), float32(res_y))) + // prepare view-dependent render data & submit draw + hg.PrepareSceneForwardPipelineViewDependentRenderData(&vid, view_state, scene, render_data, pipeline, res, views) + hg.SubmitSceneToForwardPipeline(&vid, scene, viewport.rect, view_state, pipeline, render_data, res) + } + hg.Frame() + hg.UpdateWindow(win) + } + hg.DestroyForwardPipeline(pipeline) + hg.RenderShutdown() + hg.DestroyWindow(win) +} diff --git a/scene_draw_to_texture.go b/scene_draw_to_texture.go new file mode 100644 index 0000000..b72fdb0 --- /dev/null +++ b/scene_draw_to_texture.go @@ -0,0 +1,68 @@ +package main + +import ( + "math" + + hg "github.com/harfang3d/harfang-go/v3" +) + +func main() { + hg.InputInit() + hg.WindowSystemInit() + + res_x, res_y := int32(1024), int32(1024) + win := hg.RenderInitWithWindowTitleWidthHeightResetFlags("Draw Scene to Texture", res_x, res_y, hg.RFVSync|hg.RFMSAA8X) + + hg.AddAssetsFolder("resources_compiled") + + // create pipeline + pipeline := hg.CreateForwardPipeline() + res := hg.NewPipelineResources() + + // load the scene to draw to a texture + scene := hg.NewScene() + hg.LoadSceneFromAssets("materials/materials.scn", scene, res, hg.GetForwardPipelineInfo()) + + // create a 512x512 frame buffer to draw the scene to + frame_buffer := hg.CreateFrameBufferWithWidthHeightColorFormatDepthFormatAaName(512, 512, hg.TFRGBA32F, hg.TFD24, 4, "framebuffer") // 4x MSAA + color := hg.GetColorTexture(frame_buffer) + + // create the cube model + vtx_layout := hg.VertexLayoutPosFloatNormUInt8TexCoord0UInt8() + + cube_mdl := hg.CreateCubeModel(vtx_layout, 1, 1, 1) + res.AddModel("cube", cube_mdl) + + // prepare the cube shader program + cube_prg := hg.LoadProgramFromAssets("shaders/texture") + + // main loop + angle := 0.0 + + for !hg.ReadKeyboard().Key(hg.KEscape) && hg.IsWindowOpen(win) { + dt := hg.TickClock() + angle = angle + float64(hg.TimeToSecF(dt)) + + // update scene and render to the frame buffer + scene.GetCurrentCamera().GetTransform().SetPos(hg.NewVec3WithXYZ(0, 0, float32(-(math.Sin(angle)*3.0 + 4.0)))) // animate the scene current camera on Z + + scene.Update(dt) + + view_id := uint16(0) + hg.SubmitSceneToPipelineWithFovAxisIsHorizontalFb(&view_id, scene, hg.NewIntRectWithSxSyExEy(0, 0, 512, 512), true, pipeline, res, frame_buffer.GetHandle()) + + // draw a rotating cube in immediate mode using the texture the scene was rendered to + hg.SetViewPerspective(view_id, 0, 0, res_x, res_y, hg.TranslationMat4(hg.NewVec3WithXYZ(0, 0, -1.8))) + + val_uniforms := hg.GoSliceOfUniformSetValue{hg.MakeUniformSetValueWithVec4V("color", hg.NewVec4WithXYZW(1, 1, 1, 1))} // note: these could be moved out of the main loop but are kept here for readability + tex_uniforms := hg.GoSliceOfUniformSetTexture{hg.MakeUniformSetTexture("s_tex", color, 0)} + + hg.DrawModelWithSliceOfValuesSliceOfTextures(view_id, cube_mdl, cube_prg, val_uniforms, tex_uniforms, hg.TransformationMat4(hg.NewVec3WithXYZ(0, 0, 0), hg.NewVec3WithXYZ(float32(angle*0.1), float32(angle*0.05), float32(angle*0.2)))) + + // + hg.Frame() + hg.UpdateWindow(win) + } + hg.RenderShutdown() + hg.WindowSystemShutdown() +} diff --git a/scene_instances.go b/scene_instances.go new file mode 100644 index 0000000..416c9c0 --- /dev/null +++ b/scene_instances.go @@ -0,0 +1,134 @@ +package main + +import ( + "fmt" + + hg "github.com/harfang3d/harfang-go/v3" +) + +// declare the biped actor class +type BipedActor struct { + __node *hg.Node + __scene *hg.Scene + __delay int64 + __state string + __playing_anim_ref *hg.ScenePlayAnimRef +} + +func NewBipedActor(scene *hg.Scene, res *hg.PipelineResources, pos *hg.Vec3) BipedActor { + b := BipedActor{} + + b.__node, _ = hg.CreateInstanceFromAssets(scene, hg.Mat4GetIdentity(), "biped/biped.scn", res, hg.GetForwardPipelineInfo()) + b.__node.GetTransform().SetPosRot(pos, hg.Deg3(0, hg.FRandWithRange(360), 0)) + + b.__scene = scene + b.__delay = 0 + b.__state = "" + b.__playing_anim_ref = nil + + return b +} + +func (b *BipedActor) __start_anim(name string) { + anim := b.__node.GetInstanceSceneAnim(name) // get instance specific animation + if b.__playing_anim_ref != nil { + b.__scene.StopAnim(b.__playing_anim_ref) + } + b.__playing_anim_ref = b.__scene.PlayAnimWithLoopMode(anim, hg.ALMLoop) +} +func (b *BipedActor) update(dt int64) { + // check for state change + b.__delay = b.__delay - dt + + if b.__delay <= 0 { + states := []string{"idle", "walk", "run"} + b.__state = states[hg.RandWithRange(uint32(len(states)))] + b.__delay = b.__delay + hg.TimeFromSecF(hg.FRRandWithRangeStartRangeEnd(2, 6)) // 2 to 6 seconds before next state change + b.__start_anim(b.__state) + } + // apply motion + dt_sec_f := hg.TimeToSecF(dt) + + transform := b.__node.GetTransform() + pos, rot := transform.GetPosRot() + + if b.__state == "walk" { + pos = pos.Sub(hg.GetZWithM(transform.GetWorld()).MulWithK(hg.Mtr(1.15) * dt_sec_f)) // 1.15 m/sec + rot.SetY(rot.GetY() + hg.Deg(50)*dt_sec_f) + } else if b.__state == "run" { + pos = pos.Sub(hg.GetZWithM(transform.GetWorld()).MulWithK(hg.Mtr(4.5) * dt_sec_f)) // 4.5 m/sec + rot.SetY(rot.GetY() - hg.Deg(70)*dt_sec_f) + } + + // confine actor to playground + pos = hg.ClampWithMinMax(pos, hg.NewVec3WithXYZ(-10, 0, -10), hg.NewVec3WithXYZ(10, 0, 10)) + + transform.SetPosRot(pos, rot) +} + +func (b *BipedActor) destroy() { + b.__scene.DestroyNode(b.__node) +} + +func main() { + hg.InputInit() + hg.WindowSystemInit() + + res_x, res_y := int32(1280), int32(720) + win := hg.RenderInitWithWindowTitleWidthHeightResetFlags("Scene instances", res_x, res_y, hg.RFVSync|hg.RFMSAA4X) + + hg.AddAssetsFolder("resources_compiled") + + // rendering pipeline + pipeline := hg.CreateForwardPipeline() + res := hg.NewPipelineResources() + + // load host scene + scene := hg.NewScene() + hg.LoadSceneFromAssets("playground/playground.scn", scene, res, hg.GetForwardPipelineInfo()) + + // spawn initial actors + actors := []BipedActor{} + for i := 0; i < 20; i += 1 { + actors = append(actors, NewBipedActor(scene, res, hg.RandomVec3WithMinMax(hg.NewVec3WithXYZ(-10, 0, -10), hg.NewVec3WithXYZ(10, 0, 10)))) + } + + fmt.Printf("%d nodes in scene\n", (scene.GetAllNodeCount())) + + // main loop + keyboard := hg.NewKeyboard() + + for !hg.ReadKeyboard().Key(hg.KEscape) && hg.IsWindowOpen(win) { + hg.RenderResetToWindowWithResetFlags(win, &res_x, &res_y, uint32(hg.RFVSync|hg.RFMSAA4X|hg.RFMaxAnisotropy)) + + keyboard.Update() + + if keyboard.Pressed(hg.KS) { + actors = append(actors, NewBipedActor(scene, res, hg.RandomVec3WithMinMax(hg.NewVec3WithXYZ(-10, 0, -10), hg.NewVec3WithXYZ(10, 0, 10)))) + } + if keyboard.Pressed(hg.KD) { + if len(actors) > 0 { + actors[0].destroy() + actors = actors[1:] + scene.GarbageCollect() + } + } + dt := hg.TickClock() + + for id := range actors { + actors[id].update(dt) + } + + scene.Update(dt) + + view_state := hg.ComputePerspectiveViewState(hg.Mat4LookAt(hg.NewVec3WithXYZ(0, 10, -14), hg.NewVec3WithXYZ(0, 1, -4)), hg.Deg(45), 0.01, 1000, hg.ComputeAspectRatioX(float32(res_x), float32(res_y))) + viewId := uint16(0) + hg.SubmitSceneToPipeline(&viewId, scene, hg.NewIntRectWithSxSyExEy(0, 0, res_x, res_y), view_state, pipeline, res) + + hg.Frame() + hg.UpdateWindow(win) + } + + hg.RenderShutdown() + hg.DestroyWindow(win) +} diff --git a/scene_light_priority.go b/scene_light_priority.go new file mode 100644 index 0000000..69b531f --- /dev/null +++ b/scene_light_priority.go @@ -0,0 +1,90 @@ +package main + +import ( + "math" + + hg "github.com/harfang3d/harfang-go/v3" +) + +func main() { + hg.InputInit() + hg.WindowSystemInit() + + res_x, res_y := int32(1280), int32(720) + win := hg.RenderInitWithWindowTitleWidthHeightResetFlags("Harfang - Light priority relative to a specific world position", res_x, res_y, hg.RFVSync|hg.RFMSAA4X) + + hg.AddAssetsFolder("resources_compiled") + + pipeline := hg.CreateForwardPipeline() + res := hg.NewPipelineResources() + + // create models + vtx_layout := hg.VertexLayoutPosFloatNormUInt8() + + light_mdl := hg.CreateSphereModel(vtx_layout, 0.05, 8, 16) + light_ref := res.AddModel("light", light_mdl) + orb_mdl := hg.CreateSphereModel(vtx_layout, 1, 16, 32) + orb_ref := res.AddModel("orb", orb_mdl) + ground_mdl := hg.CreateCubeModel(vtx_layout, 100, 0.01, 100) + ground_ref := res.AddModel("ground", ground_mdl) + + // create materials + shader := hg.LoadPipelineProgramRefFromAssets("core/shader/default.hps", res, hg.GetForwardPipelineInfo()) + + mat_light := hg.CreateMaterialWithValueName0Value0ValueName1Value1(shader, "uDiffuseColor", hg.NewVec4WithXYZ(0, 0, 0), "uSpecularColor", hg.NewVec4WithXYZ(0, 0, 0)) + hg.SetMaterialValueWithVec4V(mat_light, "uSelfColor", hg.NewVec4WithXYZ(1, 0.9, 0.75)) + mat_orb := hg.CreateMaterialWithValueName0Value0ValueName1Value1(shader, "uDiffuseColor", hg.NewVec4WithXYZ(1, 1, 1), "uSpecularColor", hg.NewVec4WithXYZ(1, 1, 1)) + hg.SetMaterialValueWithVec4V(mat_orb, "uSelfColor", hg.NewVec4WithXYZ(0, 0, 0)) + mat_ground := hg.CreateMaterialWithValueName0Value0ValueName1Value1(shader, "uDiffuseColor", hg.NewVec4WithXYZ(1, 1, 1), "uSpecularColor", hg.NewVec4WithXYZ(1, 1, 1)) + hg.SetMaterialValueWithVec4V(mat_ground, "uSelfColor", hg.NewVec4WithXYZ(0, 0, 0)) + + // setup scene + scene := hg.NewScene() + + cam := hg.CreateCamera(scene, hg.Mat4LookAt(hg.NewVec3WithXYZ(5, 4, -7), hg.NewVec3WithXYZ(0, 1.5, 0)), 0.01, 1000) + scene.SetCurrentCamera(cam) + + orb_node := hg.CreateObjectWithSliceOfMaterials(scene, hg.TranslationMat4(hg.NewVec3WithXYZ(0, 1, 0)), orb_ref, hg.GoSliceOfMaterial{mat_orb}) + hg.CreateObjectWithSliceOfMaterials(scene, hg.TranslationMat4(hg.NewVec3WithXYZ(0, 0, 0)), ground_ref, hg.GoSliceOfMaterial{mat_ground}) + + // create an array of dynamic lights + light_obj := scene.CreateObjectWithModelSliceOfMaterials(light_ref, hg.GoSliceOfMaterial{mat_light}) // sphere model to visualize lights + + light_nodes := []*hg.Node{} + for i := 0; i < 16; i++ { + node := hg.CreatePointLightWithDiffuseSpecular(scene, hg.Mat4GetIdentity(), 1.5, hg.NewColorWithRGBA(1, 0.85, 0.25, 1), hg.NewColorWithRGBA(1, 0.9, 0.5, 1)) + node.SetObject(light_obj) + light_nodes = append(light_nodes, node) + } + // main loop + angle := float32(0.0) + + for !hg.ReadKeyboard().Key(hg.KEscape) && hg.IsWindowOpen(win) { + dt := hg.TickClock() + + // animate lights + angle = angle + hg.TimeToSecF(dt) + + for i, node := range light_nodes { + a := float64(angle + float32(i)*hg.Deg(15)) + node.GetTransform().SetPos(hg.NewVec3WithXYZ(float32(math.Cos(a*-0.6)*math.Sin(a)*5.0), float32(math.Cos(a*1.25)*2+2.15), float32(math.Sin(a*0.5)*math.Cos(-a*0.8)*5.0))) + } + // update light priorities according to their distance to the orb + for _, node := range light_nodes { + priority := hg.Dist2WithVec3AVec3B(orb_node.GetTransform().GetPos(), node.GetTransform().GetPos()) + //priority = node.GetTransform().GetPos().y // uncomment to prioritize lights near the ground + node.GetLight().SetPriority(-priority) + } + + scene.Update(dt) + viewId := uint16(0) + hg.SubmitSceneToPipelineWithFovAxisIsHorizontal(&viewId, scene, hg.NewIntRectWithSxSyExEy(0, 0, res_x, res_y), true, pipeline, res) + + hg.Frame() + hg.UpdateWindow(win) + } + + hg.DestroyForwardPipeline(pipeline) + hg.RenderShutdown() + hg.DestroyWindow(win) +} diff --git a/scene_lua_script.go b/scene_lua_script.go new file mode 100644 index 0000000..e96cb3e --- /dev/null +++ b/scene_lua_script.go @@ -0,0 +1,50 @@ +package main + +import ( + hg "github.com/harfang3d/harfang-go/v3" +) + +func main() { + scene := hg.NewScene() + script := scene.CreateScriptWithPath("example") + + lua_vm := hg.NewSceneLuaVM() + lua_vm.CreateScriptFromSource(scene, script, ` +a = 4 + +function CallToPrintA() print("CallToPrintA: "..a) end +function CallToPrintV(v) print("CallToPrint: "..v) end +function CallToPrintScriptPath(s) print("CallToPrintScriptPath: "..s:GetPath()) end + +function CallToReturnValue() return "String returned from scene VM to host VM" end +`) + + //a := lua_vm.GetScriptValue(script, "a") + //fmt.Println("GetScriptValue returned a=" + str(lua_vm.Unpack(a))) + + //lua_vm.SetScriptValue(script, "a", lua_vm.Pack(24)) + + //a = lua_vm.GetScriptValue(script, "a") + // fmt.Println("GetScriptValue returned a=" + str(lua_vm.Unpack(a))) + + if ok, _ := lua_vm.CallWithSliceOfArgs(script, "CallToPrintA", hg.GoSliceOfLuaObject{}); !ok { + panic("CallToPrintA") + } + /*if ok, _ := lua_vm.CallWithSliceOfArgs(script, "CallToPrintV", hg.GoSliceOfLuaObject{lua_vm.Pack(8)}); !ok { + panic("CallToPrintA") + } + if ok, _ := lua_vm.CallWithSliceOfArgs(script, "CallToPrintScriptPath", hg.GoSliceOfLuaObject{lua_vm.Pack(script)}); !ok { + panic("CallToPrintA") + }*/ + + if ok, _ := lua_vm.CallWithSliceOfArgs(script, "InvalidCall", hg.GoSliceOfLuaObject{}); ok { + panic("CallToPrintA") + } + + success, _ /*rvalues*/ := lua_vm.CallWithSliceOfArgs(script, "CallToReturnValue", hg.GoSliceOfLuaObject{}) + if !success { + panic("CallToPrintA") + } + + //fmt.Println("CallToReturnValue return value=" + str(lua_vm.Unpack(rvalues[0]))) +} diff --git a/scene_many_nodes.go b/scene_many_nodes.go new file mode 100644 index 0000000..4f0163f --- /dev/null +++ b/scene_many_nodes.go @@ -0,0 +1,101 @@ +package main + +import ( + "math" + "runtime" + "runtime/debug" + + //_ "net/http/pprof" + + hg "github.com/harfang3d/harfang-go/v3" +) + +func main() { + debug.SetGCPercent(-1) + + /* go func() { + log.Println(http.ListenAndServe(":6060", nil)) + }()*/ + + hg.InputInit() + hg.WindowSystemInit() + + var resX int32 = 1280 + var resY int32 = 720 + win := hg.RenderInitWithWindowTitleWidthHeightResetFlags("Many dynamic objects", resX, resY, hg.RFMSAA4X) + + pipeline := hg.CreateForwardPipelineWithShadowMapResolution(4096) // increase shadow map resolution to 4096x4096 + res := hg.NewPipelineResources() + + // create models + vtxLayout := hg.VertexLayoutPosFloatNormUInt8() + sphereMdl := hg.CreateSphereModel(vtxLayout, 0.1, 8, 16) + sphereRef := res.AddModel("sphere", sphereMdl) + groundMdl := hg.CreateCubeModel(vtxLayout, 60, 0.001, 60) + groundRef := res.AddModel("ground", groundMdl) + + // create materials + shader := hg.LoadPipelineProgramRefFromFile("resources_compiled/core/shader/default.hps", res, hg.GetForwardPipelineInfo()) + + sphereMat := hg.CreateMaterialWithValueName0Value0ValueName1Value1(shader, "uDiffuseColor", hg.NewVec4WithXYZ(1, 0, 0), "uSpecularColor", hg.NewVec4WithXYZ(1, 0.8, 0)) + groundMat := hg.CreateMaterialWithValueName0Value0ValueName1Value1(shader, "uDiffuseColor", hg.NewVec4WithXYZ(1, 1, 1), "uSpecularColor", hg.NewVec4WithXYZ(1, 1, 1)) + + // Setup scene + scene := hg.NewScene() + scene.GetCanvas().SetColor(hg.NewColorWithRGB(0.1, 0.1, 0.1)) + scene.GetEnvironment().SetAmbient(hg.NewColorWithRGB(0.1, 0.1, 0.1)) + + cam := hg.CreateCamera(scene, hg.TransformationMat4(hg.NewVec3WithXYZ(15.5, 5, -6), hg.NewVec3WithXYZ(0.4, -1.2, 0)), 0.01, 100) + scene.SetCurrentCamera(cam) + + hg.CreateSpotLightWithDiffuseDiffuseIntensitySpecularSpecularIntensityPriorityShadowTypeShadowBias(scene, hg.TransformationMat4(hg.NewVec3WithXYZ(-8.8, 21.7, -8.8), hg.Deg3(60, 45, 0)), 0, hg.Deg(5), hg.Deg(30), hg.ColorGetWhite(), 1, hg.ColorGetWhite(), 1, 0, hg.LSTMap, 0.000005) + hg.CreateObjectWithSliceOfMaterials(scene, hg.TranslationMat4(hg.NewVec3WithXYZ(0, 0, 0)), groundRef, hg.GoSliceOfMaterial{groundMat}) + + // create scene objects + rows := [][]*hg.Transform{} + for z := float32(-100.0); z < 100.0; z += 2.0 { + row := []*hg.Transform{} + for x := float32(-100.0); x < 100.0; x += 2.0 { + node := hg.CreateObjectWithSliceOfMaterials(scene, hg.TranslationMat4(hg.NewVec3WithXYZ(x*0.1, 0.1, z*0.1)), sphereRef, hg.GoSliceOfMaterial{sphereMat}) + row = append(row, node.GetTransform()) + } + rows = append(rows, row) + } + + // main loop + angle := 0.0 + rect := hg.NewIntRectWithSxSyExEy(0, 0, resX, resY) + + for !hg.ReadKeyboard().Key(hg.KEscape) && hg.IsWindowOpen(win) { + dt := hg.TickClock() + angle += float64(hg.TimeToSecF(dt)) + + for j, row := range rows { + rowY := math.Cos(angle + float64(j)*0.1) + for i, trs := range row { + /*pos := trs.GetPos() + pos.SetY(float32(0.1 * (rowY*math.Sin(angle+float64(i)*0.1)*6 + 6.5))) + trs.SetPos(pos) + */ + p := hg.NewVec3() + p, _ = trs.GetPosRot() + p.SetY(float32(0.1 * (rowY*math.Sin(angle+float64(i)*0.1)*6 + 6.5))) + trs.SetPos(p) + + } + } + + scene.Update(dt) + + viewID := uint16(0) + hg.SubmitSceneToPipelineWithFovAxisIsHorizontal(&viewID, scene, rect, true, pipeline, res) + //hg.SubmitSceneToPipelineWithFovAxisIsHorizontal(&viewID, scene, hg.NewIntRectWithSxSyExEy(0, 0, resX, resY), true, pipeline, res) + + hg.Frame() + hg.UpdateWindow(win) + runtime.GC() + } + + hg.RenderShutdown() + hg.DestroyWindow(win) +} diff --git a/scene_pbr.go b/scene_pbr.go new file mode 100644 index 0000000..3d95683 --- /dev/null +++ b/scene_pbr.go @@ -0,0 +1,36 @@ +package main + +import ( + hg "github.com/harfang3d/harfang-go/v3" +) + +func main() { + hg.InputInit() + hg.WindowSystemInit() + + res_x, res_y := int32(940), int32(720) + win := hg.RenderInitWithWindowTitleWidthHeightResetFlags("PBR Scene", res_x, res_y, hg.RFVSync|hg.RFMSAA4X) + + pipeline := hg.CreateForwardPipeline() + res := hg.NewPipelineResources() + + hg.AddAssetsFolder("resources_compiled") + + // load scene + scene := hg.NewScene() + hg.LoadSceneFromAssets("materials/materials.scn", scene, res, hg.GetForwardPipelineInfo()) + + // main loop + for !hg.ReadKeyboard().Key(hg.KEscape) && hg.IsWindowOpen(win) { + dt := hg.TickClock() + + scene.Update(dt) + viewId := uint16(0) + hg.SubmitSceneToPipelineWithFovAxisIsHorizontal(&viewId, scene, hg.NewIntRectWithSxSyExEy(0, 0, res_x, res_y), true, pipeline, res) + + hg.Frame() + hg.UpdateWindow(win) + } + hg.RenderShutdown() + hg.DestroyWindow(win) +} diff --git a/scene_vr.go b/scene_vr.go new file mode 100644 index 0000000..54f5676 --- /dev/null +++ b/scene_vr.go @@ -0,0 +1,133 @@ +package main + +import ( + hg "github.com/harfang3d/harfang-go/v3" +) + +// Create materials +func create_material(ubc *hg.Vec4, orm *hg.Vec4, prg_ref *hg.PipelineProgramRef) *hg.Material { + mat := hg.NewMaterial() + hg.SetMaterialProgram(mat, prg_ref) + hg.SetMaterialValueWithVec4V(mat, "uBaseOpacityColor", ubc) + hg.SetMaterialValueWithVec4V(mat, "uOcclusionRoughnessMetalnessColor", orm) + return mat +} + +func main() { + hg.InputInit() + hg.WindowSystemInit() + + res_x, res_y := int32(1280), int32(720) + win := hg.RenderInitWithWindowTitleWidthHeightResetFlags("Harfang - OpenVR Scene", res_x, res_y, hg.RFVSync|hg.RFMSAA4X) + + hg.AddAssetsFolder("resources_compiled") + + pipeline := hg.CreateForwardPipeline() + res := hg.NewPipelineResources() + + render_data := hg.NewSceneForwardPipelineRenderData() // this object is used by the low-level scene rendering API to share view-independent data with both eyes + + // OpenVR initialization + if !hg.OpenVRInit() { + panic("Can't initialize OpenVR") + } + + vr_left_fb := hg.OpenVRCreateEyeFrameBufferWithAa(hg.OVRAAMSAA4x) + vr_right_fb := hg.OpenVRCreateEyeFrameBufferWithAa(hg.OVRAAMSAA4x) + + // Create models + vtx_layout := hg.VertexLayoutPosFloatNormUInt8() + + cube_mdl := hg.CreateCubeModel(vtx_layout, 1, 1, 1) + cube_ref := res.AddModel("cube", cube_mdl) + ground_mdl := hg.CreateCubeModel(vtx_layout, 50, 0.01, 50) + ground_ref := res.AddModel("ground", ground_mdl) + + // Load shader + prg_ref := hg.LoadPipelineProgramRefFromAssets("core/shader/pbr.hps", res, hg.GetForwardPipelineInfo()) + + // Create scene + scene := hg.NewScene() + scene.GetCanvas().SetColor(hg.NewColorWithRGBA(255/255, 255/255, 217/255, 1)) + scene.GetEnvironment().SetAmbient(hg.NewColorWithRGBA(15/255, 12/255, 9/255, 1)) + + hg.CreateSpotLightWithDiffuseSpecularPriorityShadowTypeShadowBias(scene, hg.TransformationMat4(hg.NewVec3WithXYZ(-8, 4, -5), hg.NewVec3WithXYZ(hg.Deg(19), hg.Deg(59), 0)), 0, hg.Deg(5), hg.Deg(30), hg.ColorGetWhite(), hg.ColorGetWhite(), 10, hg.LSTMap, 0.0001) + hg.CreatePointLightWithDiffuseSpecularPriority(scene, hg.TranslationMat4(hg.NewVec3WithXYZ(2.4, 1, 0.5)), 10, hg.NewColorWithRGBA(94.0/255.0, 255.0/255.0, 228.0/255.0, 1.0), hg.NewColorWithRGBA(94.0/255.0, 1.0, 228.0/255.0, 1.0), 0) + + mat_cube := create_material(hg.NewVec4WithXYZW(255/255, 230/255, 20/255, 1), hg.NewVec4WithXYZW(1, 0.658, 0., 1), prg_ref) + hg.CreateObjectWithSliceOfMaterials(scene, hg.TransformationMat4(hg.NewVec3WithXYZ(0, 0.5, 0), hg.NewVec3WithXYZ(0, hg.Deg(70), 0)), cube_ref, hg.GoSliceOfMaterial{mat_cube}) + + mat_ground := create_material(hg.NewVec4WithXYZW(255/255, 120/255, 147/255, 1), hg.NewVec4WithXYZW(1, 1, 0.1, 1), prg_ref) + hg.CreateObjectWithSliceOfMaterials(scene, hg.TranslationMat4(hg.NewVec3WithXYZ(0, 0, 0)), ground_ref, hg.GoSliceOfMaterial{mat_ground}) + + // Setup 2D rendering to display eyes textures + quad_layout := hg.NewVertexLayout() + quad_layout.Begin().Add(hg.APosition, 3, hg.ATFloat).Add(hg.ATexCoord0, 3, hg.ATFloat).End() + + quad_model := hg.CreatePlaneModel(quad_layout, 1, 1, 1, 1) + quad_render_state := hg.ComputeRenderStateWithDepthTestCulling(hg.BMAlpha, hg.DTDisabled, hg.FCDisabled) + + eye_t_size := float32(res_x) / 2.5 + eye_t_x := (float32(res_x)-2*eye_t_size)/6 + eye_t_size/2 + quad_matrix := hg.TransformationMat4WithScale(hg.NewVec3WithXYZ(0, 0, 0), hg.NewVec3WithXYZ(hg.Deg(90), hg.Deg(0), hg.Deg(0)), hg.NewVec3WithXYZ(eye_t_size, 1, eye_t_size)) + + tex0_program := hg.LoadProgramFromAssets("shaders/sprite") + + quad_uniform_set_value_list := hg.NewUniformSetValueList() + quad_uniform_set_value_list.Clear() + quad_uniform_set_value_list.PushBack(hg.MakeUniformSetValueWithVec4V("color", hg.NewVec4WithXYZW(1, 1, 1, 1))) + + quad_uniform_set_texture_list := hg.NewUniformSetTextureList() + + // Main loop + for !hg.ReadKeyboard().Key(hg.KEscape) && hg.IsWindowOpen(win) { + + dt := hg.TickClock() + + scene.Update(dt) + + actor_body_mtx := hg.TransformationMat4(hg.NewVec3WithXYZ(-1.3, .45, -2), hg.NewVec3WithXYZ(0, 0, 0)) + + vr_state := hg.OpenVRGetState(actor_body_mtx, 0.01, 1000) + left, right := hg.OpenVRStateToViewState(vr_state) + + vid := uint16(0) // keep track of the next free view id + passId := hg.NewSceneForwardPipelinePassViewId() + + // Prepare view-independent render data once + hg.PrepareSceneForwardPipelineCommonRenderData(&vid, scene, render_data, pipeline, res, passId) + vr_eye_rect := hg.NewIntRectWithSxSyExEy(0, 0, int32(vr_state.GetWidth()), int32(vr_state.GetHeight())) + + // Prepare the left eye render data then draw to its framebuffer + hg.PrepareSceneForwardPipelineViewDependentRenderData(&vid, left, scene, render_data, pipeline, res, passId) + hg.SubmitSceneToForwardPipelineWithFrameBuffer(&vid, scene, vr_eye_rect, left, pipeline, render_data, res, vr_left_fb.GetHandle()) + + // Prepare the right eye render data then draw to its framebuffer + hg.PrepareSceneForwardPipelineViewDependentRenderData(&vid, right, scene, render_data, pipeline, res, passId) + hg.SubmitSceneToForwardPipelineWithFrameBuffer(&vid, scene, vr_eye_rect, right, pipeline, render_data, res, vr_right_fb.GetHandle()) + + // Display the VR eyes texture to the backbuffer + hg.SetViewRect(vid, 0, 0, uint16(res_x), uint16(res_y)) + vs := hg.ComputeOrthographicViewState(hg.TranslationMat4(hg.NewVec3WithXYZ(0, 0, 0)), float32(res_y), 0.1, 100, hg.ComputeAspectRatioX(float32(res_x), float32(res_y))) + hg.SetViewTransform(vid, vs.GetView(), vs.GetProj()) + + quad_uniform_set_texture_list.Clear() + quad_uniform_set_texture_list.PushBack(hg.MakeUniformSetTexture("s_tex", hg.OpenVRGetColorTexture(vr_left_fb), 0)) + hg.SetT(quad_matrix, hg.NewVec3WithXYZ(eye_t_x, 0, 1)) + hg.DrawModelWithRenderState(vid, quad_model, tex0_program, quad_uniform_set_value_list, quad_uniform_set_texture_list, quad_matrix, quad_render_state) + + quad_uniform_set_texture_list.Clear() + quad_uniform_set_texture_list.PushBack(hg.MakeUniformSetTexture("s_tex", hg.OpenVRGetColorTexture(vr_right_fb), 0)) + hg.SetT(quad_matrix, hg.NewVec3WithXYZ(-eye_t_x, 0, 1)) + hg.DrawModelWithRenderState(vid, quad_model, tex0_program, quad_uniform_set_value_list, quad_uniform_set_texture_list, quad_matrix, quad_render_state) + + hg.Frame() + hg.OpenVRSubmitFrame(vr_left_fb, vr_right_fb) + + hg.UpdateWindow(win) + } + + hg.DestroyForwardPipeline(pipeline) + hg.RenderShutdown() + hg.DestroyWindow(win) +}