I got the idea for this while trying out the toolgun minigames and I think this would open up quite a lot of possibilities. Unfortunately, I don’t have any spare time to implement this, as I’m working on a different project.
Device BaseDevice string Name() the name of the device string Caption() the display name of the device int Version() interface version (in case this gets extended) int Width() horizontal resolution in surface-mode int Height() vertical resolution in surface-mode Catch(bool) true => catches all user input false => player can move and look around requires "catch" player Caught() returns a caught player or nil requires "catch" vector TracePos() returns the origin for a trace (SWEPs should use Player:GetShootPos()) requires "pointer" vector TraceAng() returns the angle for a trace (SWEPs should use Player:GetAimVector()) requires "pointer" bool ZoomState() true => zoomed in false => pointer mode or animating requires "zoom" bool Zooming() true => zooming in or out false => fixed position requires "zoom" Initialize() called when the device is created or reset float RenderWidth width of the screen in render-mode requires "render" float RenderHeight height of the screen in render-mode requires "render" vector VolumetricSize() the size of the larges cuboid that fits into the render-volume requires "volumetric" Add(app) adds an app to the device Remove(app) removes an app from the device Switch(app) switches to an app if it is installed Zoom(bool) true => zoom in false => pointer mode doesn't work if zooming requires "zoom" SetRenderMode(bool) true => draw using the render library, deactivate other modes false => draw on surface (like toolgun) requires "render" bool RenderMode() true => drawing using the render library false => drawing on surface (like toolgun) requires "render" SetVolumetricMode(bool) true => draw in render volume, deactivate other modes false => don't draw in render volume requires "volumetric" bool VolumetricMode() true => drawing in render volume false => not drawing in render volume requires "volumetric" App Menu() the app representing the menu requires "menu" SetMenu(App) registers an installed app as the menu requires "menu" Click(invoker, float posX, float posY) clicks on the screen the position is relative to the center of the screen or render-volume the units are share of Width() and Height() or share of RenderWidth() and RenderHeight(), respectively, depending on mode (usually ranging from -0.5 to 0.5) requires "click" Click(invoker, vector pos, vector ang) clicks on the screen the position is relative to the center of the screen, or, in volumetric mode, relative to the center of the assured render-volume the position units are share of Width() and Height(), share of RenderWidth() and RenderHeight() or share of the values in VolumetricSize(), respectively, depending on mode requires "click3D" vector GetCursor() returns the position of the cursor or nil requires "cursor" table:string Flags() defines device flags indicating non standard behavior or features (as defined for each version) flags: shade => can display color shades color => can display colors (usually used with "mono") render => supports render-mode passive => screen requires external light source (see above) click => can be clicked world => app is rendered on world model zoom => can zoom catch => can catch user input (for portable devices, seats and vehicles) pointer => can be pointed at something menu => supports a menu for choosing an app click3D => supports clicking with additional data cursor => supports a cursor volumetric => supports volumetric rendering Notes: Non standard behavior should be implemented in the device. Apps are not supposed to limit the display colors if there's a "mono"-tag. Use a shader instead. Each Pixel in surface-mode should be a square. If you're creating a device supporting render mode don't forget to push a clip plane and/or a model matrix if necessary (and don't forget shearing). A device in render-mode should mask the players screen space. The app's Draw()- and Render()-functions should only be called if the device really displays the output. Consider checking for visibility when the screen is a world model. Initialize() should do a full reset and remove all apps. Add() and Remove() should notify the app and must create a new (and unique) reference. Each app must be switched to in surface-mode. RenderWidth and RenderHeight indicate the largest rectangle visible in render-mode. At least one of these should be 1.0 unless the screen isn't a rectangle. The device is supposed to do all the initialisation so the app only needs to call surface.draw() etc. The device really should support render-mode unless it's some cheap RP stuff. Switching to an app doesn't imply calling OnActivate() (unless the device is used at the moment or it's a world model with a screen). SetMenu() must check if the app defines "menu". When Initialize() is called, the caller should add an app and switch to it. Holding reload a few seconds should reset the active app and switch to the menu after some more time. If this is not possible, there should be other means of resetting (like a button on the back of a screen). All vectors use local coordinates. A device in render-mode should use the stencil buffer to limit the screen space, one in volumetric-mode should use clip planes. All methods should be defined in the base device, along with a short desription, and should throw exceptions when called there. The device shouldn't implement error handling for missing functions.
App BaseApp string Name() the name of the app (must be unique) string Caption() the display name of the app int Version() interface version (in case this gets extended) Initialize() called when the app instance is created or the app is reset AddReference(entity) adds a reference RemoveReference(entity) removes a reference OnAdd(device) called when the app is added to a device OnRemove(device) called when the app is removed from a device OnActivate(device) called when the app is displayed on a device OnDeactivate(device) called when the app isn't displayed anymore Draw() used for drawing in surface-mode Render() used for drawing in render-mode requires "render" RenderVolume() used for drawing in volumetric-mode requires "volumetric" OnClick(device, invoker, float posX, float posY) called when someone or something clicks requires "click" OnClick3D(device, invoker, vector pos, vector ang) called when someone or something clicks requires "click3D" table:string flags() defines app flags indicating non standard behavior or features (as defined for each version) flags: menu => app can be used as menu click => app can receive clicks render => app uses render-mode click3D => app can receive 3D clicks volumetric => app uses volumetric mode Notes: Initialize() is called only once when the app instance is created. Transferring an initialized app shouldn't call it again (unless explicitly wanted). Initialize should do a full reset. The app should support being added to more than one entity. It is possible that one entity supports render-mode, while another doesn't. The app should at least display an error message in the Draw()-function when in render-mode. RemoveReference() should remove the app if the last reference is removed. If the app requires a special feature, it should look it up first and then display a descriptive error message if it isn't available. If the feature is not essential, the app should do nothing. If you want to trace something then you should use the pointer function of the device. Don't assume the invoker in OnClick() is a player. All methods should be defined in the base app, along with a short desription, and should throw exceptions when called there. The app shouldn't implement error handling for missing functions.
This is basically an interface for devices and apps running on them.
- Modular: You can use the same app on a remote control, screen or vehicle.
- Perfect for rendering camera inputs: In render-mode this shouldn’t have any visible pixelation at all.
- Supports this:
(with better graphics and without setting the air on fire)
- Configuring an entity without breaking immersion or wiring it up
- a remote control with video support
- a shooting range
- a spaceship navigation system
The base entitys should only implement stuff working without a model like switching, adding and removing apps.