* Viewports

* Support mem-points

* Update CfgVehicles.hpp

* Add some docs

* Cleanup Debugging

* Update addons/viewports/dev/debugPoints.sqf

Co-authored-by: Dystopian <sddex@ya.ru>

* Update addons/viewports/dev/debugPoints.sqf

Co-authored-by: Dystopian <sddex@ya.ru>

* Update addons/viewports/functions/fnc_eachFrame.sqf

Co-authored-by: Filip Maciejewski <veteran29@users.noreply.github.com>

* configProperties / 3den macro

* Update viewports-framework.md

* Update viewports-framework.md

* Add compats for rhs btrs

* Update addons/viewports/dev/debugPoints.sqf

Co-authored-by: Drofseh <Drofseh@users.noreply.github.com>

Co-authored-by: Dystopian <sddex@ya.ru>
Co-authored-by: Filip Maciejewski <veteran29@users.noreply.github.com>
Co-authored-by: Drofseh <Drofseh@users.noreply.github.com>
This commit is contained in:
PabstMirror 2022-05-17 11:55:09 -05:00 committed by GitHub
parent 699e286db7
commit a4258f3587
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
25 changed files with 881 additions and 0 deletions

View File

@ -0,0 +1 @@
z\ace\addons\viewports

View File

@ -0,0 +1,15 @@
class Extended_PreStart_EventHandlers {
class ADDON {
init = QUOTE(call COMPILE_SCRIPT(XEH_preStart));
};
};
class Extended_PreInit_EventHandlers {
class ADDON {
init = QUOTE(call COMPILE_SCRIPT(XEH_preInit));
};
};
class Extended_PostInit_EventHandlers {
class ADDON {
init = QUOTE(call COMPILE_SCRIPT(XEH_postInit));
};
};

View File

@ -0,0 +1,22 @@
class CfgVehicles {
class B_MBT_01_base_F;
class B_MBT_01_cannon_F: B_MBT_01_base_F { // Merkava
class ace_viewports {
class SLD_backLeftUpper {
type = "screen";
camLocation[] = {0,0,0.05};
maxDistance = 5;
camAttach[] = {0,0};
screenLocation[] = {-0.925,-3.43459,-1.07};
roles[]={"cargo"};
};
};
};
class B_MBT_01_TUSK_F: B_MBT_01_cannon_F { // Merkava TUSK (slightly different model-space because different p3d model)
class ace_viewports: ace_viewports {
class SLD_backLeftUpper: SLD_backLeftUpper {
screenLocation[] = {-0.925,-4.65511,-1.07};
};
};
};
};

View File

@ -0,0 +1,4 @@
ace_viewports
==========
Allows crew to look through periscopes

View File

@ -0,0 +1,8 @@
LOG("prep");
PREP(eachFrame);
PREP(enterVehicle);
PREP(getSeatInfo);
PREP(getViewports);
PREP(viewCleanup);
PREP(viewCreate);

View File

@ -0,0 +1,9 @@
#include "script_component.hpp"
if (!hasInterface) exitWith {};
GVAR(pfeh) = -1;
["CBA_settingsInitialized", {
TRACE_1("CBA_settingsInitialized",GVAR(enabled));
["vehicle", LINKFUNC(enterVehicle), true] call CBA_fnc_addPlayerEventHandler;
}] call CBA_fnc_addEventHandler;

View File

@ -0,0 +1,15 @@
#include "script_component.hpp"
ADDON = false;
PREP_RECOMPILE_START;
#include "XEH_PREP.hpp"
PREP_RECOMPILE_END;
#include "initSettings.sqf"
#ifdef POINT_CONFIG_DEBUG
call compileScript [QPATHTOF(dev\debugPoints.sqf)];
#endif
ADDON = true;

View File

@ -0,0 +1,3 @@
#include "script_component.hpp"
#include "XEH_PREP.hpp"

View File

@ -0,0 +1,19 @@
#include "script_component.hpp"
class CfgPatches {
class ADDON {
name = COMPONENT_NAME;
units[] = {};
weapons[] = {};
requiredVersion = REQUIRED_VERSION;
requiredAddons[] = {"ace_common"};
author = ECSTRING(common,ACETeam);
authors[] = {"PabstMirror"};
url = ECSTRING(main,URL);
VERSION_CONFIG;
};
};
#include "CfgEventHandlers.hpp"
#include "CfgVehicles.hpp"
#include "gui.hpp"

Binary file not shown.

View File

@ -0,0 +1,173 @@
#include "\z\ace\addons\viewports\script_component.hpp"
/*
[] call compileScript ["\z\ace\addons\viewports\dev\debugPoints.sqf"];
This is mostly just for placing the mem points in threeden
left-click to place and adjust current point
alt+left-click to place next point
alt+right-click to output
shift+right-click to reset
// Tweak:
z = (vehicle player) getVariable "ace_viewports_viewports";
p = z # 0 # 4; z # 0 set [4, p vectorAdd [0,0.1,0]];
// Place by view:
v = (positionCameraToWorld [0,0,0.4]);
m = (vehicle player) worldToModel v;
z = (vehicle player) getVariable "ace_viewports_viewports";
z # 0 set [4, m];
*/
#define IDD_3DEN 313
[] spawn {
INFO_2("Pre-Init [is3den %1][3den display: %2]", is3den, !isNull findDisplay IDD_3DEN);
if (!is3den) exitWith {};
GVAR(3denIndex) = 0;
GVAR(3denViewports) = [];
disableSerialization;
private _3den = findDisplay IDD_3DEN;
if (_3den getVariable [QGVAR(setup), false]) exitWith {};
_3den setVariable [QGVAR(setup), true];
_3den displayAddEventHandler ["MouseButtonDown", {
params ["", "_button", "_mouseX", "_mouseY", "_shift", "_ctrl", "_alt"];
if (_shift && _button == 1) exitWith {
systemChat "Reset/Reload";
if ((supportInfo "u:diag_mergeConfigFile") isNotEqualTo []) then {
call compile 'diag_mergeConfigFile ["P:\z\ace\addons\viewports\config.cpp"]';
};
{ _x setVariable [QGVAR(viewports), nil] } forEach vehicles;
GVAR(3denIndex) = 0;
GVAR(3denViewports) = [];
true
};
if (_alt) then {
if (count GVAR(3denViewports) > GVAR(3denIndex)) then {
systemChat "Advance to next index";
GVAR(3denIndex) = GVAR(3denIndex) + 1;
};
};
if (_alt && _button == 1) exitWith {
private _vehicle = (get3DENSelected "object") param [0, objNull];
private _config = configOf _vehicle;
private _model = getText (_config >> "model");
while {true} do {
private _parent = inheritsFrom _config;
if ((getText (_parent >> "model")) != _model) exitWith {};
_config = _parent;
};
private _out = [];
_out pushBack format [" class %1: %2 {", configName _config, configName inheritsFrom _config];
_out pushBack format [" class ace_viewports {"];
{
_x params ["_name", "", "_camLocation", "_camAttach"];
_out pushBack format [' class %1 {', _name];
_out pushBack format [' camLocation[] = {%1, %2, %3};', _camLocation # 0, _camLocation # 1, _camLocation # 2];
_out pushBack format [' camAttach = %1;', _camAttach];
// _out pushBack format [' type = "%1";', _type];
// _out pushBack format [' screenLocation[] = {};'];
// _out pushBack format [' maxDistance = 99;'];
// _out pushBack format [' compartments[]={};'];
// _out pushBack format [' roles[]={};'];
_out pushBack format [' };'];
} forEach GVAR(3denViewports);
_out pushBack format [' };'];
_out pushBack format [' };'];
// Some inherited configs might use a different model which uses a different offset - yuck
private _inherited = '((configName _x) isKindOf (configName _config)) && {_model != getText (_x >> "model")}' configClasses (configFile >> "CfgVehicles");
_out pushBack format ["// Watch out for %1", _inherited apply {configName _x}];
copyToClipboard (_out joinString endl);
systemChat format ["copied %1 lines", count _out];
};
if (_button == 0) exitWith {
private _vehicle = (get3DENSelected "object") param [0, objNull];
if (isNull _vehicle) exitWith {};
private _start = AGLToASL positionCameraToWorld [0,0,0];
private _end = AGLToASL screenToWorld [_mouseX, _mouseY];
private _intersections = lineIntersectsSurfaces [_start, _end];
private _pointASL = _intersections # 0 # 0;
if (isNil "_pointASL") exitWith {};
_pointASL = _pointASL vectorAdd [0,0,0.09]; // Add a little bit up because it always sinks into the model
private _pointMS = _vehicle worldToModel ASLtoAGL _pointASL;
private _name = format ["view_%1",GVAR(3denIndex)];
// [_name, _type, _camLocation, _camAttach, _screenLocation, _maxDistance, _compartments, _roles]
GVAR(3denViewports) set [GVAR(3denIndex), [_name, "", _pointMS, 0, _pointMS, 99, [], []]];
true
};
}];
};
// this runs in both threeden and in-game
addMissionEventHandler ["Draw3D", {
private _vehicle = vehicle player;
private _viewports = _vehicle getVariable [QGVAR(viewports), []];
if (is3den) then {
_vehicle = (get3DENSelected "object") param [0, objNull];
if (isNull _vehicle) exitWith {};
_viewports = [_vehicle] call FUNC(getViewports);
if (GVAR(3denViewports) isNotEqualTo []) then {
_viewports = GVAR(3denViewports);
};
};
if (isNull _vehicle) exitWith {};
drawIcon3D ["#(argb,8,8,3)color(1,1,1,1)", [1,1,0,1], _vehicle modelToWorldVisual [0,0,0], 0.1, 0.1, 0, "", 1, 0.02, "TahomaB"];
if (alive player) then { // not using ace_player so this works in 3den
drawIcon3D ["#(argb,8,8,3)color(1,1,1,1)", [0,1,0,1], aslToAGL eyepos player, 0.1, 0.1, 0, "eye", 1, 0.02, "TahomaB"];
drawIcon3D ["#(argb,8,8,3)color(1,1,1,1)", [0,1,0,1], player modelToWorldVisual (player selectionPosition "pilot"), 0.1, 0.1, 0, "pilot", 1, 0.02, "TahomaB"];
};
// {
// private _pos = _vehicle modelToWorldVisual (_vehicle selectionPosition [_x, "Memory"]);
// drawIcon3D ["#(argb,8,8,3)color(1,1,1,1)", [0,0,1,0.2], _pos, 0.05, 0.05, 0, _x, 1, 0.02, "TahomaB"];
// } forEach (_vehicle selectionNames "Memory");
{
_x params ["_name", "_type", "_camLocation", "_camAttach", "_screenLocation", "_maxDistance", "_compartments", "_roles"];
if (_camLocation isEqualType "") then {
_camLocation = _vehicle selectionPosition [_camLocation, "Memory"];
};
private _screenAGL = _vehicle modelToWorldVisual _screenLocation;
drawIcon3D ["#(argb,8,8,3)color(0,0,1,1)", [1,0.5,1,1], _screenAGL, 0.05, 0.05, 0, format ["%1:%2",_forEachIndex,_compartments], 1, 0.03, "TahomaB"];
private _camAGL = if (_camAttach isEqualType 0) then {
_vehicle modelToWorldVisual _camLocation
} else {
private _turretConfig = [_vehicle, _camAttach] call CBA_fnc_getTurret;
private _memoryPointGunnerOptics = getText(_turretConfig >> "memoryPointGunnerOptics");
_vehicle modelToWorldVisual (_camLocation vectorAdd (_vehicle selectionPosition _memoryPointGunnerOptics))
};
drawIcon3D ["#(argb,8,8,3)color(1,0,0,1)", [0.5,1,1,1], _camAGL, 0.1, 0.1, 0, format ["%1:%2",_forEachIndex,_name], 1, 0.03, "TahomaB"];
if (_camAttach isEqualType 0) then {
private _camAGL = _vehicle modelToWorldVisual _camLocation;
drawIcon3D ["#(argb,8,8,3)color(1,0,0,1)", [1,1,1,1], _camAGL, 0.1, 0.1, 0, _name, 1, 0.05, "TahomaB"];
private _target = _vehicle modelToWorldVisual (_camLocation vectorAdd ([1, _camAttach, 0] call CBA_fnc_polar2vect));
drawLine3D [_camAGL, _target, [0,1,0,1]];
private _target = _vehicle modelToWorldVisual (_camLocation vectorAdd ([1, _camAttach, 1] call CBA_fnc_polar2vect));
drawLine3D [_camAGL, _target, [0,1,0,1]];
private _target = _vehicle modelToWorldVisual (_camLocation vectorAdd ([1, _camAttach, -1] call CBA_fnc_polar2vect));
drawLine3D [_camAGL, _target, [0,1,0,1]];
private _target = _vehicle modelToWorldVisual (_camLocation vectorAdd ([0.2, _camAttach+90, 0] call CBA_fnc_polar2vect));
drawLine3D [_camAGL, _target, [1,0,1,1]];
private _target = _vehicle modelToWorldVisual (_camLocation vectorAdd ([0.2, _camAttach-90, 0] call CBA_fnc_polar2vect));
drawLine3D [_camAGL, _target, [1,0,1.2,1]];
};
} forEach _viewports;
}];

View File

@ -0,0 +1,77 @@
#include "script_component.hpp"
/*
* Author: PabstMirror
* Runs each frame while inside of a vehicle with viewports
*
* Arguments:
* 0: PFEH Args <ARRAY>
* 0: Player <OBJECT>
* 1: Vehicle <OBJECT>
* 2: Viewport configuration <ARRAY>
* 3: Viewport index shown (-1 for none) <NUMBER>
* 4: Last visionmode <NUMBER>
*
* Return Value:
* None
*
* Example:
* [] call ace_viewports_fnc_eachFrame
*
* Public: No
*/
params ["_args", "_pfID"];
_args params ["_player", "_vehicle", "_viewports", "_shownIndex", "_lastVisionMode"];
private _newIndex = -1;
if (cba_events_control) then {
if (cameraView != "INTERNAL") exitWith {};
if (isTurnedOut _player) exitWith {};
if (!([_player, _vehicle, []] call EFUNC(common,canInteractWith))) exitWith {};
BEGIN_COUNTER(newIndex);
if ((_shownIndex > -1) && {currentVisionMode _player != _lastVisionMode}) then {
// Vision Mode Changed - Force stop cam and restart
call FUNC(viewCleanup);
_shownIndex = -1;
};
([_player] call FUNC(getSeatInfo)) params ["_role", "", "", "_comparment"];
private _newIndexAngle = 45; // Controls the max angle
private _eyesPosASL = AGLtoASL (positionCameraToWorld [0, 0, 0]);
private _eyesDir = (AGLtoASL (positionCameraToWorld [0, 0, 1])) vectorDiff _eyesPosASL;
{
_x params ["", "", "_camLocation", "", "_screenLocation", "_maxDistance", "_compartments", "_roles"];
private _viewASL = AGLtoASL (_vehicle modelToWorldVisual _screenLocation);
private _viewDiff = _viewASL vectorDiff _eyesPosASL;
private _viewAngle = acos (_viewDiff vectorCos _eyesDir);
#ifdef DEBUG_MODE_FULL
systemChat format ["%1: %2 @ %3",_forEachIndex,round _viewAngle, vectorMagnitude _viewDiff];
#endif
if (
(_viewAngle < _newIndexAngle)
&& {(_compartments isEqualTo []) || {(toLower _comparment) in _compartments}}
&& {(_roles isEqualTo []) || {(toLower _role) in _roles}}
&& {(vectorMagnitude _viewDiff) < _maxDistance}
) then {
_newIndex = _forEachIndex;
_newIndexAngle = _viewAngle;
};
} forEach _viewports;
END_COUNTER(newIndex);
};
if (_shownIndex == _newIndex) exitWith {}; // No-change - fast exit
if (_shownIndex > -1) then {
call FUNC(viewCleanup);
};
if (_newIndex > -1) then {
[_vehicle, _viewports # _newIndex, currentVisionMode _player] call FUNC(viewCreate);
_args set [4, currentVisionMode _player];
};
_args set [3, _newIndex];

View File

@ -0,0 +1,36 @@
#include "script_component.hpp"
/*
* Author: PabstMirror
* Handle playerEH for new changing vehicle, check if it has any viewports and start PFEH
*
* Arguments:
* 0: player <OBJECT>
* 1: vehicle <OBJECT>
*
* Return Value:
* None
*
* Example:
* [player, vehicle player] call ace_viewports_fnc_enterVehicle
*
* Public: No
*/
params ["_player", "_vehicle"];
TRACE_2("enterVehicle",_player,_vehicle);
if (GVAR(pfeh) != -1) then {
TRACE_1("cleaning up",GVAR(pfeh));
[GVAR(pfeh)] call CBA_fnc_removePerFrameHandler;
GVAR(pfeh) = -1;
call FUNC(viewCleanup);
};
if (!GVAR(enabled)) exitWith {};
if (_player == _vehicle) exitWith {};
private _viewports = [_vehicle] call FUNC(getViewports);
if (_viewports isEqualTo []) exitWith {};
GVAR(pfeh) = [LINKFUNC(eachFrame), 0, [_player, _vehicle, _viewports, -1, -1]] call CBA_fnc_addPerFrameHandler;
TRACE_3("start pfeh",GVAR(pfeh),typeOf _vehicle,count _viewports);

View File

@ -0,0 +1,46 @@
#include "script_component.hpp"
/*
* Author: Dystopian, PabstMirror
* Adapted from quickmount's addFreeSeatsActions
*
* Arguments:
* 0: Unit <OBJECT>
*
* Return Value:
* ARRAY
*
* Example:
* [player] call ace_viewports_fnc_getSeatInfo
*
* Public: No
*/
params ["_unit"];
private _vehicle = vehicle _unit;
if (_vehicle == _unit) exitWith { [] };
private _vehicleConfig = configOf _vehicle;
private _fullCrew = fullCrew [_vehicle, "", false];
(_fullCrew select (_fullCrew findIf {_unit == _x select 0})) params ["", "_role", "_cargoIndex", "_turretPath"];
private _compartment = switch (_role) do {
case "driver": {
(_vehicleConfig >> "driverCompartments") call BIS_fnc_getCfgData
};
case "cargo": {
// note: cargoNumber is different from the cargoIndex from fullCrew...
private _cargoNumber = fullCrew [_vehicle, "cargo", true] findIf {_unit == _x select 0};
private _cargoCompartments = getArray (_vehicleConfig >> "cargoCompartments");
private _cargoCompartmentsLast = count _cargoCompartments - 1;
_cargoCompartments select (_cargoNumber min _cargoCompartmentsLast)
};
default {
private _turretConfig = [_vehicleConfig, _turretPath] call CBA_fnc_getTurret;
(_turretConfig >> "gunnerCompartments") call BIS_fnc_getCfgData
};
};
if (!(_compartment isEqualType "")) then { _compartment = format ["Compartment%1",_compartment] };
[_role, _cargoIndex, _turretPath, _compartment]

View File

@ -0,0 +1,74 @@
#include "script_component.hpp"
/*
* Author: PabstMirror
* Gets viewports for a vehicle from config. Caches results to a setVar on the vic.
*
* Arguments:
* 0: vehicle <OBJECT>
*
* Return Value:
* ARRAY
*
* Example:
* [vehicle player] call ace_viewports_fnc_getViewports
*
* Public: No
*/
params ["_vehicle"];
private _viewports = _vehicle getVariable [QGVAR(viewports), nil];
if (isNil "_viewports") then {
_viewports = (configProperties [(configOf _vehicle) >> "ace_viewports", "isClass _x", true]) apply {
// name [STRING] is just used for debug
private _name = configName _x;
// type [STRING] - Optional
private _type = getText (_x >> "type");
// camLocation [ARRAY or STRING] - Required
private _camLocation = if (isArray (_x >> "camLocation")) then {
getArray (_x >> "camLocation") // modelOffset
} else {
getText (_x >> "camLocation") // memPoint
};
// camAttach [ARRAY or NUMBER] - Required
private _camAttach = if (isArray (_x >> "camAttach")) then {
getArray (_x >> "camAttach") // turret
} else {
getNumber (_x >> "camAttach") // angle
};
// screenLocation [ARRAY or STRING] - Optional (will be converted to ARRAY here!)
private _screenLocation = if (isArray (_x >> "screenLocation")) then {
getArray (_x >> "screenLocation") // modelOffset
} else {
getText (_x >> "screenLocation") // memPoint
};
if (_screenLocation isEqualType "") then {
// screens should be on the hull (IE non-animated) so we can do all the mem-point calculations here
if (_screenLocation == "") exitWith { // use generic periscope drop height from cam
private _camLocArray = if (_camLocation isEqualType []) then {
_camLocation
} else {
_vehicle selectionPosition [_camLocation, "Memory"];
};
_screenLocation =_camLocArray vectorAdd [0,0,-0.175]
};
_screenLocation = _vehicle selectionPosition [_screenLocation, "Memory"];
};
// maxDistance [NUMBER] - Optional
private _maxDistance = getNumber (_x >> "maxDistance");
if (_maxDistance == 0) then {
_maxDistance = 0.8;
};
// compartments [ARRAY] - Optional
private _compartments = (getArray (_x >> "compartments")) apply {toLower _x};
// roles [ARRAY] - Optional
private _roles = (getArray (_x >> "roles")) apply {toLower _x};
[_name, _type, _camLocation, _camAttach, _screenLocation, _maxDistance, _compartments, _roles]
};
TRACE_3("getViewports",_vehicle,typeOf _vehicle,count _viewports);
_vehicle setVariable [QGVAR(viewports), _viewports];
};
_viewports

View File

@ -0,0 +1,28 @@
#include "script_component.hpp"
/*
* Author: PabstMirror
* Cleans up existing viewport display and camera
*
* Arguments:
* None
*
* Return Value:
* None
*
* Example:
* [] call ace_viewports_fnc_viewCleanup
*
* Public: No
*/
TRACE_1("camCleanup",_this);
if (!isNull (missionNamespace getVariable [QGVAR(camera), objNull])) then {
GVAR(camera) cameraEffect ["terminate", "back", QGVAR(pip0)];
camDestroy GVAR(camera);
};
private _display = uiNamespace getVariable [QGVAR(display), displayNull];
if (!isNull _display) then {
QGVAR(display) cutText ["", "PLAIN"];
};

View File

@ -0,0 +1,129 @@
#include "script_component.hpp"
/*
* Author: PabstMirror
* Creates a viewport display and camera
*
* Arguments:
* 0: Vehicle <OBJECT>
* 1: Viewport <ARRAY>
* 2: Player's vision mode <NUMBER>
*
* Return Value:
* None
*
* Example:
* [...] call ace_viewports_fnc_viewCreate
*
* Public: No
*/
params ["_vehicle", "_viewport", "_visionMode"];
_viewport params ["_name", "_type", "_camLocation", "_camAttach"];
TRACE_5("camCreate",_vehicle,_name,_type,_camLocation,_camAttach);
private _usingGoggles = _visionMode > 0;
if (_camLocation isEqualType "") then {
_camLocation = _vehicle selectionPosition [_camLocation, "Memory"];
if (_camLocation isEqualTo [0,0,0]) then { WARNING_2("probably bad cam location %1:%2",typeOf _vehicle,_viewport); }
};
// Create Cam and attach it to vic
GVAR(camera) = "camera" camCreate getPos _vehicle;
if (_camAttach isEqualType 0) then {
// number - Static attach and set const direction
GVAR(camera) attachTo [_vehicle, _camLocation];
GVAR(camera) setDir _camAttach; // could do pitch as well, but probably not needed
} else {
// array - Turret path, get gunner optic mem and bone-attach to it
private _turretConfig = [_vehicle, _camAttach] call CBA_fnc_getTurret;
private _memoryPointGunnerOptics = getText(_turretConfig >> "memoryPointGunnerOptics");
GVAR(camera) attachTo [_vehicle, _camLocation, _memoryPointGunnerOptics, true];
};
// Setup r2texture
GVAR(camera) cameraEffect ["INTERNAL", "BACK", QGVAR(pip0)];
private _renderTexture = format ["#(argb,512,512,1)r2t(%1,1)", QGVAR(pip0)];
// Create blank display
QGVAR(display) cutRsc [QGVAR(display), "PLAIN", 0, false];
private _display = uiNamespace getVariable [QGVAR(display), displayNull];
// R2T aspect ratio parameter has no effect - it will match main video AR
// better to have ui elements squashed than to squash the R2T
private _screenAR = getResolution select 4;
private _camEffect = [0];
private _camFov = 0.75;
switch (true) do {
case (_type == "screen"): {
// Generic "Squad Leader's Display" monitor showing turret cam
private _desiredAR = 1.25;
private _stretch = (_desiredAR / _screenAR) max 0.8 min 1.25; // define max stretch factor of pip texture (don't stretch more or less than this)
private _viewHeight = 0.3 * safeZoneH;
private _viewWidth = _stretch * _viewHeight * _screenAR / 1.3333333333333;
private _ctrlRender = _display ctrlCreate ["RscPicture", -1];
_ctrlRender ctrlSetText _renderTexture;
_ctrlRender ctrlSetPosition [safezoneX + 0.5 * safezoneW - 0.5 * _viewWidth, safezoneY + 0.5 * safeZoneH - 0.5 * _viewHeight, _viewWidth, _viewHeight];
_ctrlRender ctrlCommit 0;
private _ctrlOverlay = _display ctrlCreate ["RscPicture", -1];
_ctrlOverlay ctrlSetText "\a3\weapons_f\reticle\data\optika_tv_ca.paa";
_ctrlOverlay ctrlSetPosition [safezoneX + 0.5 * safezoneW - 0.5 * _viewWidth, safezoneY + 0.5 * safeZoneH - 0.5 * _viewHeight, _viewWidth, _viewHeight];
_ctrlOverlay ctrlCommit 0;
if (_usingGoggles) then {
// Screen will be out of focus, too bright and not in IR; should be almost impossible to see anything useful
_camEffect = [3,1,1,0.1,0,[0,0,0,0],[1,1,1,0],[1,1,1,1]];
private _ctrlNVG = _display ctrlCreate ["RscPicture", -1];
_ctrlNVG ctrlSetText "#(argb,8,8,3)color(1,1,0.6,0.9)";
_ctrlNVG ctrlSetPosition [safezoneX + 0.5 * safezoneW - 0.5 * _viewWidth, safezoneY + 0.5 * safeZoneH - 0.5 * _viewHeight, _viewWidth, _viewHeight];
_ctrlNVG ctrlCommit 0;
} else {
_camEffect = [0]; // 2.08's currentVisionMode change could allow matching real turret's vision mode
};
_camFov = 0.25;
};
default {
// Generic periscope viewport
private _desiredAR = 3;
private _stretch = (_desiredAR / _screenAR) max 0.8 min 1.25; // define max stretch factor of pip texture
private _viewHeight = 0.3 * safeZoneH;
if (_usingGoggles) then {
_camEffect = [_visionMode]; // pass-thru
// _camEffect = [3, true, 0.747773,0.791092,0,[0,0,0,0],[1.3,1.2,0,0.9],[6,1,1,0]];
// Some periscope glass is IR Laser Safe (~1064nm) which is close to same wavelength as NVGs
// And cannot apply nvg and ace_nightvision effects to pip at same time, so just make it small and shitty...
_viewHeight = 0.45 * _viewHeight;
};
private _viewWidth = _stretch * _viewHeight * _screenAR / 1.3333333333333;
private _ctrlRender = _display ctrlCreate ["RscPicture", -1];
_ctrlRender ctrlSetText _renderTexture;
_ctrlRender ctrlSetPosition [safezoneX + 0.5 * safezoneW - 0.5 * _viewWidth, safezoneY + 0.5 * safeZoneH - 0.5 * _viewHeight, _viewWidth, _viewHeight];
_ctrlRender ctrlCommit 0;
if (_usingGoggles) then {
// Roughly try to color match ace_nvg, and make it semi-opaque
private _ctrlNVG = _display ctrlCreate ["RscPicture", -1];
_ctrlNVG ctrlSetText "#(argb,8,8,3)color(0.25,0.2,0.05,0.75)";
_ctrlNVG ctrlSetPosition [safezoneX + 0.5 * safezoneW - 0.5 * _viewWidth, safezoneY + 0.5 * safeZoneH - 0.5 * _viewHeight, _viewWidth, _viewHeight];
_ctrlNVG ctrlCommit 0;
};
private _ctrlOverlay = _display ctrlCreate ["RscPicture", -1];
_ctrlOverlay ctrlSetText QPATHTOF(data\optic_window_ca.paa);
_ctrlOverlay ctrlSetPosition [safezoneX + 0.5 * safezoneW - 0.5 * _viewWidth, safezoneY + 0.5 * safeZoneH - 0.5 * _viewHeight, _viewWidth, _viewHeight];
_ctrlOverlay ctrlCommit 0;
};
};
GVAR(camera) camSetFov _camFov;
QGVAR(pip0) setPiPEffect _camEffect;
GVAR(camera) camCommit 0;

View File

@ -0,0 +1 @@
#include "\z\ace\addons\viewports\script_component.hpp"

11
addons/viewports/gui.hpp Normal file
View File

@ -0,0 +1,11 @@
class RscTitles {
class GVAR(display) {
idd = -1;
onLoad = QUOTE( with uiNameSpace do { GVAR(display) = _this select 0 }; );
movingEnable = 0;
duration = 9999999;
fadeIn = 0;
fadeOut = 0;
class controls {};
};
};

View File

@ -0,0 +1,9 @@
[
QGVAR(enabled), "CHECKBOX",
[LELSTRING(common,Enabled), LLSTRING(setting_enabled_description)],
[ELSTRING(common,ACEKeybindCategoryVehicles), LSTRING(addon_displayname)],
true,
true,
{},
false // Doesn't need full mission restart, but you have to exit and re-enter vic
] call CBA_fnc_addSetting;

View File

@ -0,0 +1,18 @@
#define COMPONENT viewports
#define COMPONENT_BEAUTIFIED Viewports
#include "\z\ace\addons\main\script_mod.hpp"
// #define DEBUG_MODE_FULL
// #define DISABLE_COMPILE_CACHE
// #define ENABLE_PERFORMANCE_COUNTERS
// #define POINT_CONFIG_DEBUG
#ifdef DEBUG_ENABLED_VIEWPORTS
#define DEBUG_MODE_FULL
#endif
#ifdef DEBUG_SETTINGS_VIEWPORTS
#define DEBUG_SETTINGS DEBUG_SETTINGS_VIEWPORTS
#endif
#include "\z\ace\addons\main\script_macros.hpp"

View File

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<Project name="ACE">
<Package name="Viewports">
<Key ID="STR_ACE_Viewports_addon_displayname">
<English>Viewports</English>
</Key>
<Key ID="STR_ACE_Viewports_setting_enabled_description">
<English>Allows crew to look through periscopes</English>
</Key>
</Package>
</Project>

View File

@ -0,0 +1,24 @@
---
layout: wiki
title: Viewports
description: Allows crew to look through periscopes.
group: feature
category: interaction
parent: wiki
mod: ace
version:
major: 3
minor: x
patch: y
---
## 1. Overview
Allows crew to look through periscopes.
## 2. Usage
- Hold <kbd>Ctrl</kbd>
- Look at a supported periscope or display monitor
## 3. Dependencies
{% include dependencies_list.md component="viewports" %}

View File

@ -0,0 +1,56 @@
---
layout: wiki
title: Viewports Framework
description: How to configure a vehicle for viewports
group: framework
order: 5
parent: wiki
mod: ace
version:
major: 3
minor: x
patch: y
---
## 1. Config Values
Reference [ace_viewports_fnc_getViewports](https://github.com/acemod/ACE3/blob/master/addons/viewports/functions/fnc_getViewports.sqf)
```cpp
class myVehicle {
class ace_viewports {
class Template {
// type [STRING] - Optional
type = "";
// camLocation [ARRAY or STRING] - Required
camLocation = "memoryPointP1";
camLocation[] = {1,2,3}; // model offset
// camAttach [ARRAY or NUMBER] - Required
camAttach[] = {0,0}; // Turret path
camAttach = 55; // Direction in degrees
// screenLocation [ARRAY or STRING] - Optional
screenLocation = "memoryPointP1x";
screenLocation[] = {1,2,3};
// maxDistance [NUMBER] - Optional
maxDistance = 0.75;
// compartments [ARRAY] - Optional
compartments[]={"Compartment1"};
// roles [ARRAY] - Optional
roles[]={"cargo"};
};
class periscope_0 {
camLocation[] = {0.987915, -0.324707, -0.0673385};
camAttach = 70;
roles[]={"cargo"};
};
class commandersView {
screenLocation[] = {0.729126,-0.191597,-0.573349};
maxDistance = 5;
type = "screen";
camLocation[] = {0,0,0.05};
camAttach[] = {0,0};
roles[]={"cargo"};
};
};
};
```

View File

@ -226,11 +226,103 @@ class CfgVehicles {
}; };
class rhs_btr70_vmf: rhs_btr_base { class rhs_btr70_vmf: rhs_btr_base {
EGVAR(refuel,fuelCapacity) = 350; EGVAR(refuel,fuelCapacity) = 350;
class ace_viewports {
class view_0 {
camLocation[] = {0.478394, -0.575, -0.145};
camAttach = 90;
compartments[]={"Compartment1"};
roles[]={"cargo"};
};
class view_1 {
camLocation[] = {-1.38184, -0.575, -0.145};
camAttach = -90;
compartments[]={"Compartment1"};
roles[]={"cargo"};
};
};
}; };
class rhs_btr70_msv: rhs_btr70_vmf {}; class rhs_btr70_msv: rhs_btr70_vmf {};
class rhs_btr80_msv: rhs_btr70_msv { class rhs_btr80_msv: rhs_btr70_msv {
EGVAR(refuel,fuelCapacity) = 300; EGVAR(refuel,fuelCapacity) = 300;
class ace_viewports {
class view_0 {
camLocation[] = {0.534424, -0.336914, 0.636819};
camAttach = 45;
compartments[]={"Compartment1"};
roles[]={"cargo"};
};
class view_1 {
camLocation[] = {0.760254, -0.459473, 0.526328};
camAttach = 90;
compartments[]={"Compartment1"};
roles[]={"cargo"};
};
class view_2 {
camLocation[] = {0.770508, -1.21924, 0.526954};
camAttach = 90;
compartments[]={"Compartment1"};
roles[]={"cargo"};
};
class view_3 {
camLocation[] = {-1.13, -1.2085, 0.490339};
camAttach = -90;
compartments[]={"Compartment1"};
roles[]={"cargo"};
};
class view_4 {
camLocation[] = {-1.14124, -0.416992, 0.460611};
camAttach = -90;
compartments[]={"Compartment1"};
roles[]={"cargo"};
};
class view_5 {
camLocation[] = {-0.932983, -0.326172, 0.647666};
camAttach = -45;
compartments[]={"Compartment1"};
roles[]={"cargo"};
};
};
};
class rhs_btr80a_msv: rhs_btr80_msv {
class ace_viewports {
class view_0 {
camLocation[] = {0.589844, -0.314941, 0.449678};
camAttach = 45;
compartments[]={"Compartment1"};
roles[]={"cargo"};
};
class view_1 {
camLocation[] = {0.809082, -0.442871, 0.276865};
camAttach = 90;
compartments[]={"Compartment1"};
roles[]={"cargo"};
};
class view_2 {
camLocation[] = {0.819092, -1.24414, 0.27857};
camAttach = 90;
compartments[]={"Compartment1"};
roles[]={"cargo"};
};
class view_3 {
camLocation[] = {-1.1012, -1.22461, 0.341089};
camAttach = -90;
compartments[]={"Compartment1"};
roles[]={"cargo"};
};
class view_4 {
camLocation[] = {-1.11597, -0.458984, 0.307256};
camAttach = -90;
compartments[]={"Compartment1"};
roles[]={"cargo"};
};
class view_5 {
camLocation[] = {-0.869995, -0.304688, 0.461181};
camAttach = -45;
compartments[]={"Compartment1"};
roles[]={"cargo"};
};
};
}; };
class rhs_2s3tank_base: Tank_F { class rhs_2s3tank_base: Tank_F {