diff --git a/README.md b/README.md index 44333cd..fff959b 100644 --- a/README.md +++ b/README.md @@ -7,19 +7,13 @@ nim-csfml Warning ------- -This library consists of class wrappers implemented as `ptr object`. Because Nim does not allow attaching pointers to the garbage collector, I decided to use [destructors][nim-destructors] hoping that would be a reasonable way to implement automatic disposal of objects. However, this feature is based on lexical scoping, which (as I later realized) makes things problematic: the disposal behavior is more like normal `object`s rather than `ref objects`, and sometimes unpredictable. - -It is recommended to disable destructors (pass `-d:csfmlNoDestructors` to the compiler) and dispose of the `ptr object`s manually by calling `destroy`. Standard memory management caveats apply: destroying objects that are still used will break things, forgetting to destroy is a memory leak. - -There is no good way to fix this under the current state of the language, short of reimplementing everything with additional wrapper classes which also add a lot of overhead. +This library consists of class wrappers implemented as `ptr object`. Because Nim does not allow attaching pointers to the garbage collector, disposal of objects is not implemented and needs to be manual, by calling the `destroy` methods. Standard memory management caveats apply: destroying objects that are still used will break things, forgetting to destroy is a memory leak. [More details](https://github.com/BlaXpirit/nim-csfml/issues/6) This library is not under active development, but detailed bug reports will be given proper attention. - - Introduction ------------ @@ -29,7 +23,7 @@ The API attempts to be very similar to SFML's, but some general changes are pres - To construct an object (`sf::SomeType x(param)`), use a corresponding procedure (there are 2 variations): - `var x = newSomeType(param)`, which means it is a `ptr object`. - - Such objects have [destructors][nim-destructors] associated with them (no need to call `destroy` manually). + - Such objects need to have `destroy` called to properly dispose of them. - Never create them using `new`. - `var x = someType(param)`, which means it is an `object` (in CSFML it corresponds to a simple `struct`). - `Vector2(i|f)`, `Vector3f` and `(Int|Float)Rect` should be created using special `vec2`, `vec3` and `rect` procs. @@ -102,7 +96,6 @@ This library uses and is based on [SFML][] and [CSFML][]. [csfml]: http://www.sfml-dev.org/download/csfml/ [sfml-tutorials]: http://www.sfml-dev.org/tutorials/ [nim]: http://nim-lang.org/ -[nim-destructors]: http://nim-lang.org/docs/manual.html#type-bound-operations-destructors [python]: http://python.org/ [nimble]: https://github.com/nim-lang/nimble [nimrod-sfml]: https://github.com/fowlmouth/nimrod-sfml diff --git a/examples/flippy_bird.nim b/examples/flippy_bird.nim index c1f9d98..556a0d3 100644 --- a/examples/flippy_bird.nim +++ b/examples/flippy_bird.nim @@ -37,3 +37,7 @@ while window.open: window.draw bird window.display() + +bird.destroy() +bird_texture.destroy() +window.destroy() diff --git a/examples/gl.nim b/examples/gl.nim index 7f41c77..9f03aa0 100644 --- a/examples/gl.nim +++ b/examples/gl.nim @@ -25,4 +25,6 @@ while window.open: glColor3f(0.0, 0.5, 1.0); glVertex2f( 0.0, -1.0) glEnd() - window.display() \ No newline at end of file + window.display() + +window.destroy() diff --git a/examples/pong.nim b/examples/pong.nim index 41eafc8..4b3be5e 100644 --- a/examples/pong.nim +++ b/examples/pong.nim @@ -178,3 +178,14 @@ while window.open: # Display things on screen window.display() + +clock.destroy() +AITimer.destroy() +pauseMessage.destroy() +font.destroy() +ball.destroy() +rightPaddle.destroy() +leftPaddle.destroy() +ballSound.destroy() +ballSoundBuffer.destroy() +window.destroy() diff --git a/examples/shader.nim b/examples/shader.nim index 66c35d3..0d3922b 100644 --- a/examples/shader.nim +++ b/examples/shader.nim @@ -59,3 +59,12 @@ while window.open: window.draw text, renderStates(shader=wbShader) window.display() + +clock.destroy() +window.destroy() +wbShader.destroy() +text.destroy() +font.destroy() +pxShader.destroy() +sprite.destroy() +texture.destroy() diff --git a/examples/shapes.nim b/examples/shapes.nim index fad3859..c19eb2c 100644 --- a/examples/shapes.nim +++ b/examples/shapes.nim @@ -21,6 +21,7 @@ while window.open: vertexArray.append vertex(vec2(100, 0), Red) vertexArray.append vertex(vec2(0, 100), Blue) window.draw vertexArray + vertexArray.destroy() # Top right var vertexSeq = @[ @@ -38,6 +39,7 @@ while window.open: convexShape[2] = vec2(0, 100) convexShape.fillColor = Green window.draw convexShape + convexShape.destroy() # Bottom right proc getPointCount(p: pointer): int {.cdecl.} = 3 @@ -50,5 +52,8 @@ while window.open: customShape.update() customShape.fillColor = Green window.draw customShape + customShape.destroy() window.display() + +window.destroy() diff --git a/examples/simple.nim b/examples/simple.nim index 73ba7fe..eaae60f 100644 --- a/examples/simple.nim +++ b/examples/simple.nim @@ -8,3 +8,5 @@ while window.open: if event.kind == EventType.Closed: window.close() window.display() + +window.destroy() diff --git a/examples/snakes.nim b/examples/snakes.nim index a8e028c..13058b1 100644 --- a/examples/snakes.nim +++ b/examples/snakes.nim @@ -54,6 +54,7 @@ proc draw[T](self: Food, target: T, states: RenderStates) = circle.position = vec2(self.position)+vec2(0.05, 0.05) circle.fill_color = self.color target.draw circle, states + circle.destroy() @@ -107,6 +108,7 @@ proc draw[T](self: Snake, target: T, states: RenderStates) = segment.position = vec2(current)+vec2(0.05, 0.05) segment.fill_color = self.color target.draw segment, states + segment.destroy() # The following is eye candy and may be removed # but change the above to RectangleShape of size (0.9, 0.9) @@ -124,6 +126,7 @@ proc draw[T](self: Snake, target: T, states: RenderStates) = connection.position = vec2(current)+vec2(float(d.x)/2.0+0.05, float(d.y)/2.0+0.05) connection.fill_color = self.color target.draw connection, states + connection.destroy() # Draw eyes with a darkened color var eye = new_CircleShape(radius=0.2/2) @@ -136,6 +139,7 @@ proc draw[T](self: Snake, target: T, states: RenderStates) = eye.position = self.body[0]+vec2(0.4, 0.4)-delta target.draw eye, states + eye.destroy() proc new_Field(size: Vector2i): Field = @@ -222,3 +226,5 @@ while window.open: window.draw field, states window.display() + +window.destroy() diff --git a/examples/sound_capture.nim b/examples/sound_capture.nim index 4e3e4e0..63ddeb2 100644 --- a/examples/sound_capture.nim +++ b/examples/sound_capture.nim @@ -41,5 +41,7 @@ else: while sound.status == SoundStatus.Playing: echo "Playing... ", sound.playingOffset.asSeconds, " sec" sleep 100.milliseconds + sound.destroy() +recorder.destroy() echo "Done!" diff --git a/examples/test_graphics.nim b/examples/test_graphics.nim index 0a354a6..94b1713 100644 --- a/examples/test_graphics.nim +++ b/examples/test_graphics.nim @@ -14,4 +14,5 @@ block: let s = "Випробування" var txt = newText() txt.str = s - assert txt.str == s \ No newline at end of file + assert txt.str == s + txt.destroy() diff --git a/examples/test_system.nim b/examples/test_system.nim index bef6c5d..bc621be 100644 --- a/examples/test_system.nim +++ b/examples/test_system.nim @@ -28,3 +28,4 @@ block: assert t2 > 50000 assert t2 < 150000 + clock.destroy() diff --git a/examples/typing.nim b/examples/typing.nim index d07ac35..b07c945 100644 --- a/examples/typing.nim +++ b/examples/typing.nim @@ -36,3 +36,7 @@ while window.open: window.clear White window.draw text window.display() + +text.destroy() +font.destroy() +window.destroy() diff --git a/generate/generate.py b/generate/generate.py index 08a1c16..eb28107 100644 --- a/generate/generate.py +++ b/generate/generate.py @@ -188,8 +188,6 @@ def handle_function(main, params): main_sgn = 'proc {nfname}{public}({sparams}): {nftype}' main_fn = '{nfname}' pragmas = [] - if nfname=='destroy': - pragmas.append('destroy') if nfname.startswith('get') and nfname[3].isupper() and len(params)==1: nfname = nfname[3].lower()+nfname[4:] elif nfname.startswith('is') and nfname[2].isupper() and len(params)==1: diff --git a/src/csfml/private/audio_gen.nim b/src/csfml/private/audio_gen.nim index 76cde52..e7a80fa 100644 --- a/src/csfml/private/audio_gen.nim +++ b/src/csfml/private/audio_gen.nim @@ -147,7 +147,7 @@ proc newMusic*(stream: var InputStream): Music {. ## *Returns:* A new Music object (NULL if failed) proc destroy*(music: Music) {. - destroy, cdecl, importc: "sfMusic_destroy".} + cdecl, importc: "sfMusic_destroy".} ## Destroy a music ## ## *Arguments*: @@ -427,7 +427,7 @@ proc copy*(sound: Sound): Sound {. ## *Returns:* A new Sound object which is a copy of ``sound`` proc destroy*(sound: Sound) {. - destroy, cdecl, importc: "sfSound_destroy".} + cdecl, importc: "sfSound_destroy".} ## Destroy a sound ## ## *Arguments*: @@ -745,7 +745,7 @@ proc copy*(soundBuffer: SoundBuffer): SoundBuffer {. ## *Returns:* A new SoundBuffer object which is a copy of ``soundBuffer`` proc destroy*(soundBuffer: SoundBuffer) {. - destroy, cdecl, importc: "sfSoundBuffer_destroy".} + cdecl, importc: "sfSoundBuffer_destroy".} ## Destroy a sound buffer ## ## *Arguments*: @@ -834,7 +834,7 @@ proc newSoundBufferRecorder*(): SoundBufferRecorder {. ## *Returns:* A new SoundBufferRecorder object (NULL if failed) proc destroy*(soundBufferRecorder: SoundBufferRecorder) {. - destroy, cdecl, importc: "sfSoundBufferRecorder_destroy".} + cdecl, importc: "sfSoundBufferRecorder_destroy".} ## Destroy a sound buffer recorder ## ## *Arguments*: @@ -911,7 +911,7 @@ proc newSoundRecorder*(onStart: SoundRecorderStartCallback, onProcess: SoundReco ## *Returns:* A new SoundRecorder object (NULL if failed) proc destroy*(soundRecorder: SoundRecorder) {. - destroy, cdecl, importc: "sfSoundRecorder_destroy".} + cdecl, importc: "sfSoundRecorder_destroy".} ## Destroy a sound recorder ## ## *Arguments*: @@ -1054,7 +1054,7 @@ proc newSoundStream*(onGetData: SoundStreamGetDataCallback, onSeek: SoundStreamS ## *Returns:* A new SoundStream object proc destroy*(soundStream: SoundStream) {. - destroy, cdecl, importc: "sfSoundStream_destroy".} + cdecl, importc: "sfSoundStream_destroy".} ## Destroy a sound stream ## ## *Arguments*: diff --git a/src/csfml/private/common.nim b/src/csfml/private/common.nim index 807518b..a465bef 100644 --- a/src/csfml/private/common.nim +++ b/src/csfml/private/common.nim @@ -21,12 +21,6 @@ {.deadCodeElim: on.} -when defined(csfmlNoDestructors): - {.pragma: destroy.} -else: - {.experimental.} - {.pragma: destroy, override.} - when defined(windows): const lib = "csfml-" & module & "-2.dll" diff --git a/src/csfml/private/graphics_gen.nim b/src/csfml/private/graphics_gen.nim index a89bdc7..aca8b69 100644 --- a/src/csfml/private/graphics_gen.nim +++ b/src/csfml/private/graphics_gen.nim @@ -375,7 +375,7 @@ proc copy*(shape: CircleShape): CircleShape {. ## *Returns:* Copied object proc destroy*(shape: CircleShape) {. - destroy, cdecl, importc: "sfCircleShape_destroy".} + cdecl, importc: "sfCircleShape_destroy".} ## Destroy an existing circle Shape ## ## *Arguments*: @@ -735,7 +735,7 @@ proc copy*(shape: ConvexShape): ConvexShape {. ## *Returns:* Copied object proc destroy*(shape: ConvexShape) {. - destroy, cdecl, importc: "sfConvexShape_destroy".} + cdecl, importc: "sfConvexShape_destroy".} ## Destroy an existing convex Shape ## ## *Arguments*: @@ -1132,7 +1132,7 @@ proc copy*(font: Font): Font {. ## *Returns:* Copied object proc destroy*(font: Font) {. - destroy, cdecl, importc: "sfFont_destroy".} + cdecl, importc: "sfFont_destroy".} ## Destroy an existing font ## ## *Arguments*: @@ -1315,7 +1315,7 @@ proc copy*(image: Image): Image {. ## *Returns:* Copied object proc destroy*(image: Image) {. - destroy, cdecl, importc: "sfImage_destroy".} + cdecl, importc: "sfImage_destroy".} ## Destroy an existing image ## ## *Arguments*: @@ -1468,7 +1468,7 @@ proc copy*(shape: RectangleShape): RectangleShape {. ## *Returns:* Copied object proc destroy*(shape: RectangleShape) {. - destroy, cdecl, importc: "sfRectangleShape_destroy".} + cdecl, importc: "sfRectangleShape_destroy".} ## Destroy an existing rectangle shape ## ## *Arguments*: @@ -1834,7 +1834,7 @@ proc newRenderTexture*(width: cint, height: cint, depthBuffer: BoolInt): RenderT ## *Returns:* A new RenderTexture object, or NULL if it failed proc destroy*(renderTexture: RenderTexture) {. - destroy, cdecl, importc: "sfRenderTexture_destroy".} + cdecl, importc: "sfRenderTexture_destroy".} ## Destroy an existing render texture ## ## *Arguments*: @@ -2152,7 +2152,7 @@ proc newRenderWindow*(handle: WindowHandle, settings: ContextSettings): RenderWi newRenderWindow(handle, Csettings) proc destroy*(renderWindow: RenderWindow) {. - destroy, cdecl, importc: "sfRenderWindow_destroy".} + cdecl, importc: "sfRenderWindow_destroy".} ## Destroy an existing render window ## ## *Arguments*: @@ -2677,7 +2677,7 @@ proc newShader*(vertexShaderStream: var InputStream, fragmentShaderStream: var I ## *Returns:* A new Shader object, or NULL if it failed proc destroy*(shader: Shader) {. - destroy, cdecl, importc: "sfShader_destroy".} + cdecl, importc: "sfShader_destroy".} ## Destroy an existing shader ## ## *Arguments*: @@ -2896,7 +2896,7 @@ proc newShape*(getPointCount: ShapeGetPointCountCallback, getPoint: ShapeGetPoin ## *Returns:* A new Shape object proc destroy*(shape: Shape) {. - destroy, cdecl, importc: "sfShape_destroy".} + cdecl, importc: "sfShape_destroy".} ## Destroy an existing shape ## ## *Arguments*: @@ -3239,7 +3239,7 @@ proc copy*(sprite: Sprite): Sprite {. ## *Returns:* Copied object proc destroy*(sprite: Sprite) {. - destroy, cdecl, importc: "sfSprite_destroy".} + cdecl, importc: "sfSprite_destroy".} ## Destroy an existing sprite ## ## *Arguments*: @@ -3512,7 +3512,7 @@ proc copy*(text: Text): Text {. ## *Returns:* Copied object proc destroy*(text: Text) {. - destroy, cdecl, importc: "sfText_destroy".} + cdecl, importc: "sfText_destroy".} ## Destroy an existing text ## ## *Arguments*: @@ -3904,7 +3904,7 @@ proc copy*(texture: Texture): Texture {. ## *Returns:* Copied object proc destroy*(texture: Texture) {. - destroy, cdecl, importc: "sfTexture_destroy".} + cdecl, importc: "sfTexture_destroy".} ## Destroy an existing texture ## ## *Arguments*: @@ -4068,7 +4068,7 @@ proc copy*(transformable: Transformable): Transformable {. ## *Returns:* Copied object proc destroy*(transformable: Transformable) {. - destroy, cdecl, importc: "sfTransformable_destroy".} + cdecl, importc: "sfTransformable_destroy".} ## Destroy an existing transformable ## ## *Arguments*: @@ -4233,7 +4233,7 @@ proc copy*(vertexArray: VertexArray): VertexArray {. ## *Returns:* Copied object proc destroy*(vertexArray: VertexArray) {. - destroy, cdecl, importc: "sfVertexArray_destroy".} + cdecl, importc: "sfVertexArray_destroy".} ## Destroy an existing vertex array ## ## *Arguments*: @@ -4363,7 +4363,7 @@ proc copy*(view: View): View {. ## *Returns:* Copied object proc destroy*(view: View) {. - destroy, cdecl, importc: "sfView_destroy".} + cdecl, importc: "sfView_destroy".} ## Destroy an existing view ## ## *Arguments*: diff --git a/src/csfml/private/system_gen.nim b/src/csfml/private/system_gen.nim index 50232c1..5cec137 100644 --- a/src/csfml/private/system_gen.nim +++ b/src/csfml/private/system_gen.nim @@ -90,7 +90,7 @@ proc copy*(clock: Clock): Clock {. ## *Returns:* A new Clock object which is a copy of ``clock`` proc destroy*(clock: Clock) {. - destroy, cdecl, importc: "sfClock_destroy".} + cdecl, importc: "sfClock_destroy".} ## Destroy a clock ## ## *Arguments*: diff --git a/src/csfml/private/window_gen.nim b/src/csfml/private/window_gen.nim index 955596f..296c381 100644 --- a/src/csfml/private/window_gen.nim +++ b/src/csfml/private/window_gen.nim @@ -20,7 +20,7 @@ proc newContext*(): Context {. ## *Returns:* New Context object proc destroy*(context: Context) {. - destroy, cdecl, importc: "sfContext_destroy".} + cdecl, importc: "sfContext_destroy".} ## Destroy a context ## ## *Arguments*: @@ -478,7 +478,7 @@ proc newWindow*(handle: WindowHandle, settings: ContextSettings): Window = newWindow(handle, Csettings) proc destroy*(window: Window) {. - destroy, cdecl, importc: "sfWindow_destroy".} + cdecl, importc: "sfWindow_destroy".} ## Destroy a window ## ## *Arguments*: