[Cuis-dev] Webcam support
Juan Vuletich
juan at cuis.st
Wed Jun 24 12:07:10 PDT 2026
Just pushed some updates to Morphic, essentially to support #outOfWorld:.
The attach includes the previous one I sent today, together with a
couple of simplifications.
Now the camera should turn off correctly. Please review for integration
into Camera.pck.st.
Cheers!
On 2026-06-24 2:07 PM, Juan Vuletich via Cuis-dev wrote:
> Just pushed #flipBy:on: to the repo. The attach is my suggestion for
> CameraMorph. Please review it.
>
> Also keep in mind that if you resize the CameraMorph stretching
> differently in x and y (changing the aspect ratio), then rotation will
> look weird, as in Cuis we assume scale is just a number.
>
> Thanks,
>
> On 2026-06-24 1:47 PM, Juan Vuletich via Cuis-dev wrote:
>> Hi Luciano!
>>
>> This is so cool! Just pushed it to the Cuis repo.
>>
>> We need to add #outOfWorld: to Cuis. Let me take a look.
>>
>> One thing that is not working well is scaling and rotation. To fix
>> it, I suggest moving the mirroring of the frame to #nextFrame, for
>> instance by adding this at the end:
>>
>> orientation == #natural ifTrue: [
>> displayForm := displayForm flippedBy: #horizontal ].
>>
>> If you agree, we'd need to keep both the original and mirrored frames
>> to avoid allocating a new Form on every frame.
>>
>> Thanks,
>>
>> On 2026-06-23 10:36 AM, Luciano Notarfrancesco via Cuis-dev wrote:
>>> This package implements basic webcam support using the CameraPlugin
>>> included in the stock VM. It's just a quick port from Squeak, I
>>> didn't spend a lot of time on it... but at least it seems to work
>>> fine on MacOS. Let me know of any problems.
>>>
>>> To test it, you can just open a new CameraMorph, for example
>>> printing this on a workspace:
>>> CameraMorph new inspect
>>>
>>> There's a context menu to turn it on/off, set natural/original
>>> orientation, change resolution, etc.
>>>
>>> If you close it before turning it off, depending on how you close it
>>> it might not stop the camera (because #delete is not always
>>> sent, how to know when a morph goes outside the world?). If this
>>> happens just run CameraMorph allOff.
>>>
>>> Cheers,
>>> Luciano
>>>
>>>
--
Juan Vuletich
www.cuis.st
github.com/jvuletich
researchgate.net/profile/Juan-Vuletich
independent.academia.edu/JuanVuletich
patents.justia.com/inventor/juan-manuel-vuletich
-------------- next part --------------
'From Cuis7.9 [latest update: #8020] on 24 June 2026 at 3:58:15 pm'!
!classDefinition: #CameraMorph category: #Camera!
BoxMorph subclass: #CameraMorph
instanceVariableNames: 'cameraNumber resolution orientation cameraIsOn displayForm captureDelayMs showFPS framesSinceLastDisplay lastDisplayTime fps capturedForm '
classVariableNames: ''
poolDictionaries: ''
category: 'Camera'!
!CameraMorph methodsFor: 'drawing' stamp: 'jmv 24/Jun/2026, 4:35:54 pm (UTC)'!
drawCameraImageOn: aCanvas
| scale offset |
scale := 1 @ 1.
offset := 0 @ 0.
extent = displayForm extent ifFalse: [scale := extent / displayForm extent].
1 @ 1 = scale
ifTrue: [aCanvas image: displayForm at: offset]
ifFalse:
[| originalTransformation |
originalTransformation := aCanvas currentTransformation.
aCanvas geometryTransformation: (originalTransformation copy translatedBy: offset; scaledBy: scale).
aCanvas image: displayForm at: 0 @ 0.
aCanvas geometryTransformation: originalTransformation].! !
!CameraMorph methodsFor: 'private' stamp: 'jmv 24/Jun/2026, 4:54:23 pm (UTC)'!
initializeDisplayForm
| displayExtent cameraExtent formExtent |
displayExtent := self extentForResolutionName: resolution.
cameraExtent := CameraInterface frameExtent: cameraNumber.
cameraExtent isZero
ifTrue: [formExtent := displayExtent]
ifFalse: [ | camRatio frameRatio |
formExtent := cameraExtent.
camRatio := cameraExtent x / cameraExtent y.
frameRatio := displayExtent x / displayExtent y.
camRatio ~= frameRatio ifTrue: [displayExtent := displayExtent x @ (displayExtent x * camRatio reciprocal)]].
capturedForm := Form extent: formExtent depth: 32.
displayForm := capturedForm.
self morphExtent: displayExtent.! !
!CameraMorph methodsFor: 'private' stamp: 'jmv 24/Jun/2026, 6:37:55 pm (UTC)'!
intoWorld: aWorld
super intoWorld: aWorld.
cameraIsOn ifFalse: [self off].! !
!CameraMorph methodsFor: 'private' stamp: 'jmv 24/Jun/2026, 4:54:53 pm (UTC)'!
nextFrame
| frameCount |
frameCount := CameraInterface getFrameForCamera: cameraNumber into: capturedForm bits.
frameCount = 0 ifTrue: [self increaseCaptureDelay].
frameCount > 2 ifTrue: [self decreaseCaptureDelay].
framesSinceLastDisplay := framesSinceLastDisplay + frameCount.
orientation == #natural
ifTrue: [
displayForm == capturedForm
ifTrue: [ displayForm := Form extent: capturedForm extent depth: 32 ].
capturedForm flipBy: #horizontal on: displayForm ]
ifFalse: [ displayForm := capturedForm ].! !
!CameraMorph methodsFor: 'private' stamp: 'jmv 24/Jun/2026, 6:36:22 pm (UTC)'!
outOfWorld: aWorld
super outOfWorld: aWorld.
cameraIsOn ifTrue: [self off].! !
!methodRemoval: CameraMorph #delete stamp: 'jmv 24/Jun/2026, 6:57:51 pm (UTC)'!
CameraMorph removeSelector: #delete!
!classDefinition: #CameraMorph category: #Camera!
BoxMorph subclass: #CameraMorph
instanceVariableNames: 'cameraNumber resolution orientation cameraIsOn capturedForm displayForm captureDelayMs showFPS framesSinceLastDisplay lastDisplayTime fps'
classVariableNames: ''
poolDictionaries: ''
category: 'Camera'!
More information about the Cuis-dev
mailing list