2017-11-14 15:27:48 +01:00
|
|
|
import * as THREE from 'three';
|
|
|
|
import undoable from 'redux-undo';
|
|
|
|
import undoFilter from '../utils/undoFilter.js';
|
|
|
|
import * as actions from '../actions/index.js';
|
|
|
|
import * as d2Tools from '../constants/d2Tools.js';
|
|
|
|
import * as d3Tools from '../constants/d3Tools.js';
|
2017-12-07 16:43:20 +01:00
|
|
|
import { COLOR_STRING_TO_HEX } from '../constants/general.js';
|
2017-11-14 15:27:48 +01:00
|
|
|
import * as contextTools from '../constants/contextTools.js';
|
|
|
|
import { ERASER_SIZES, BRUSH_SIZES } from '../constants/d2Constants.js';
|
|
|
|
import update from 'react-addons-update';
|
|
|
|
import { defaultCamera, cameraReducer } from './d3/tools/cameraReducer.js';
|
|
|
|
import d2AddImageReducer from './d2/addImageReducer.js';
|
|
|
|
import d2ToolReducer from './d2/toolReducer.js';
|
|
|
|
import d3ToolReducer from './d3/toolReducer.js';
|
|
|
|
import d2PinchZoomReducer from './d2/pinchZoomReducer.js';
|
|
|
|
import d2WheelZoomReducer from './d2/wheelZoomReducer.js';
|
|
|
|
import d2PanZoomReducer from './d2/panReducer.js';
|
|
|
|
import selectionReducer from './selectionReducer.js';
|
|
|
|
import selectionOperationReducer from './selectionOperationReducer.js';
|
|
|
|
import contextReducer from './contextReducer.js';
|
|
|
|
import { Matrix, Vector } from 'cal';
|
|
|
|
import {
|
|
|
|
setActiveSpace, addSpaceActive, setActive2D, removeAllObjects, getActive2D, addObject
|
|
|
|
} from './objectReducers.js';
|
|
|
|
import menusReducer from './menusReducer.js';
|
|
|
|
// import createDebug from 'debug';
|
|
|
|
// const debug = createDebug('d3d:reducer:sketcher');
|
|
|
|
|
|
|
|
const initialState = {
|
|
|
|
spaces: {
|
|
|
|
world: {
|
|
|
|
matrix: new THREE.Matrix4(),
|
|
|
|
objectIds: []
|
|
|
|
}
|
|
|
|
},
|
|
|
|
objectsById: {},
|
|
|
|
activeSpace: 'world',
|
|
|
|
objectIdCounter: 0,
|
|
|
|
context: {
|
2017-11-29 13:37:32 +01:00
|
|
|
solid: true,
|
2017-12-07 16:43:20 +01:00
|
|
|
color: COLOR_STRING_TO_HEX[contextTools.LIGHT_BLUE_B]
|
2017-11-14 15:27:48 +01:00
|
|
|
},
|
|
|
|
selection: {
|
|
|
|
transform: new Matrix(),
|
|
|
|
// array of objects (one per selected object),
|
|
|
|
// containing the object id and it's initialTransform (pre selection transform)
|
|
|
|
objects: []
|
|
|
|
},
|
|
|
|
d2: {
|
|
|
|
brush: {
|
|
|
|
size: BRUSH_SIZES[contextTools.BRUSH_SIZE_MEDIUM]
|
|
|
|
},
|
|
|
|
eraser: {
|
|
|
|
active: false,
|
|
|
|
size: ERASER_SIZES[contextTools.ERASER_SIZE_MEDIUM]
|
|
|
|
},
|
|
|
|
transform: {
|
|
|
|
active: false,
|
|
|
|
handle: '',
|
|
|
|
dragSelect: {
|
|
|
|
start: new Vector(),
|
|
|
|
end: new Vector()
|
|
|
|
}
|
|
|
|
},
|
|
|
|
trace: {
|
|
|
|
start: new Vector(),
|
|
|
|
position: new Vector(),
|
|
|
|
active: false,
|
|
|
|
floodFillData: {
|
|
|
|
edge: [],
|
|
|
|
fill: []
|
|
|
|
}
|
|
|
|
},
|
|
|
|
tool: d2Tools.FREE_HAND,
|
|
|
|
toolbar: {
|
|
|
|
open: []
|
|
|
|
},
|
2017-11-15 15:13:49 +01:00
|
|
|
canvasMatrix: new Matrix()
|
2017-11-14 15:27:48 +01:00
|
|
|
},
|
|
|
|
d3: {
|
|
|
|
height: {
|
|
|
|
handle: '',
|
|
|
|
active: false
|
|
|
|
},
|
|
|
|
twist: {
|
|
|
|
rotation: 0,
|
|
|
|
active: false
|
|
|
|
},
|
|
|
|
sculpt: {
|
|
|
|
handles: [],
|
|
|
|
activeHandle: null
|
|
|
|
},
|
|
|
|
tool: d3Tools.HEIGHT,
|
|
|
|
toolbar: {
|
|
|
|
open: []
|
|
|
|
},
|
2017-11-15 15:13:49 +01:00
|
|
|
camera: defaultCamera
|
2017-11-14 15:27:48 +01:00
|
|
|
},
|
|
|
|
menus: menusReducer(undefined, {})
|
|
|
|
};
|
|
|
|
|
|
|
|
function sketcherReducer(state = initialState, action) {
|
|
|
|
// if (action.log !== false) debug(action.type);
|
|
|
|
|
|
|
|
switch (action.category) {
|
|
|
|
case actions.CAT_SELECTION:
|
|
|
|
const preSelectionState = state;
|
|
|
|
state = selectionReducer(state, action);
|
|
|
|
// if selection changed
|
|
|
|
if (state.selection.objects !== preSelectionState.selection.objects) {
|
|
|
|
state = d2ToolReducer(state, action);
|
|
|
|
state = d3ToolReducer(state, action);
|
|
|
|
state = updateMenus(state, action);
|
|
|
|
state = contextReducer(state, action);
|
|
|
|
}
|
|
|
|
return state;
|
|
|
|
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (action.type) {
|
|
|
|
case actions.ADD_OBJECT:
|
|
|
|
return addObject(state, action.objectData);
|
|
|
|
|
|
|
|
case actions.D2_DRAG_START:
|
|
|
|
case actions.D2_DRAG:
|
|
|
|
case actions.D2_DRAG_END:
|
|
|
|
case actions.D2_TAP:
|
|
|
|
case actions.TRACE_DRAG:
|
|
|
|
case actions.TRACE_DRAG_END:
|
|
|
|
case actions.TRACE_TAP:
|
|
|
|
case `${actions.FLOOD_FILL}_PENDING`:
|
|
|
|
case `${actions.FLOOD_FILL}_FULFILLED`:
|
|
|
|
case `${actions.FLOOD_FILL}_REJECTED`:
|
|
|
|
case `${actions.TRACE_FLOOD_FILL}_PENDING`:
|
|
|
|
case `${actions.TRACE_FLOOD_FILL}_FULFILLED`:
|
|
|
|
case `${actions.TRACE_FLOOD_FILL}_REJECTED`:
|
|
|
|
case actions.TRANSFORM_START:
|
|
|
|
case actions.TRANSFORM:
|
|
|
|
case actions.TRANSFORM_END:
|
|
|
|
case actions.MULTITOUCH_TRANSFORM_START:
|
|
|
|
case actions.MULTITOUCH_TRANSFORM:
|
|
|
|
case actions.MULTITOUCH_TRANSFORM_END:
|
|
|
|
case actions.D2_TEXT_INIT:
|
|
|
|
case actions.D2_TEXT_INPUT_CHANGE:
|
|
|
|
case actions.D2_TEXT_ADD:
|
|
|
|
case actions.MOVE_SELECTION:
|
|
|
|
return d2ToolReducer(state, action);
|
|
|
|
|
|
|
|
case `${actions.ADD_IMAGE}_FULFILLED`:
|
|
|
|
return d2AddImageReducer(state, action);
|
|
|
|
|
|
|
|
case actions.D2_MOUSE_WHEEL:
|
|
|
|
return d2WheelZoomReducer(state, action);
|
|
|
|
|
|
|
|
case actions.D2_SECOND_DRAG:
|
|
|
|
return d2PanZoomReducer(state, action);
|
|
|
|
|
|
|
|
case actions.D2_MULTITOUCH_START:
|
|
|
|
case actions.D2_MULTITOUCH:
|
|
|
|
case actions.D2_MULTITOUCH_END:
|
|
|
|
state = d2ToolReducer(state, action);
|
|
|
|
state = d2PinchZoomReducer(state, action);
|
|
|
|
return state;
|
|
|
|
|
|
|
|
case actions.D3_DRAG_START:
|
|
|
|
case actions.D3_DRAG:
|
|
|
|
case actions.D3_DRAG_END:
|
|
|
|
case actions.D3_SECOND_DRAG_START:
|
|
|
|
case actions.D3_SECOND_DRAG:
|
|
|
|
case actions.D3_SECOND_DRAG_END:
|
|
|
|
case actions.D3_TAP:
|
|
|
|
case actions.D3_MOUSE_WHEEL:
|
|
|
|
case actions.D3_MULTITOUCH_START:
|
|
|
|
case actions.D3_MULTITOUCH:
|
|
|
|
case actions.D3_MULTITOUCH_END:
|
|
|
|
case actions.HEIGHT_START:
|
|
|
|
case actions.HEIGHT:
|
|
|
|
case actions.HEIGHT_END:
|
|
|
|
case actions.TWIST_START:
|
|
|
|
case actions.TWIST:
|
|
|
|
case actions.TWIST_END:
|
|
|
|
case actions.SCULPT_START:
|
|
|
|
case actions.SCULPT:
|
|
|
|
case actions.SCULPT_END:
|
|
|
|
case actions.ADD_SCULPT_HANDLE:
|
|
|
|
case actions.REMOVE_SCULPT_HANDLE:
|
|
|
|
case actions.STAMP:
|
|
|
|
return d3ToolReducer(state, action);
|
|
|
|
|
|
|
|
case actions.D2_CHANGE_TOOL:
|
|
|
|
state = setActive2D(state, null);
|
|
|
|
state = selectionReducer(state, action);
|
|
|
|
state = d2ToolReducer(state, action); // switch and initialize tool
|
|
|
|
state = updateMenus(state, action);
|
|
|
|
state = contextReducer(state, action);
|
|
|
|
return state;
|
|
|
|
|
|
|
|
case actions.D3_CHANGE_TOOL:
|
|
|
|
state = d3ToolReducer(state, action); // switch and initialize tool
|
|
|
|
state = updateMenus(state, action);
|
|
|
|
return state;
|
|
|
|
|
|
|
|
case actions.CONTEXT_CHANGE_TOOL:
|
|
|
|
state = contextReducer(state, action);
|
|
|
|
state = updateMenus(state, action);
|
|
|
|
return state;
|
|
|
|
|
|
|
|
case actions.CLEAR:
|
2017-11-23 17:57:16 +01:00
|
|
|
return update(initialState, {});
|
2017-11-14 15:27:48 +01:00
|
|
|
|
2017-11-14 19:02:29 +01:00
|
|
|
case actions.OPEN_SKETCH:
|
|
|
|
let first = true;
|
|
|
|
for (const space of action.data.data.spaces) {
|
|
|
|
if (first) {
|
2017-11-23 16:07:54 +01:00
|
|
|
if (!state.spaces.world) state = addSpaceActive(state, space.matrix, 'world');
|
2017-11-14 19:02:29 +01:00
|
|
|
} else {
|
|
|
|
state = addSpaceActive(state, space.matrix);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (const object of space.objects) {
|
|
|
|
if (first) {
|
|
|
|
state = addObject(state, { ...object, space: 'world' });
|
|
|
|
} else {
|
|
|
|
state = addObject(state, object);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
first = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return setActiveSpace(state, 'world');
|
|
|
|
|
2017-11-14 15:27:48 +01:00
|
|
|
case actions.DUPLICATE_SELECTION:
|
|
|
|
case actions.DELETE_SELECTION:
|
|
|
|
case actions.UNION:
|
|
|
|
case actions.INTERSECT:
|
|
|
|
return selectionOperationReducer(state, action);
|
|
|
|
|
|
|
|
case actions.MENU_OPEN:
|
|
|
|
case actions.MENU_CLOSE:
|
|
|
|
return updateMenus(state, action);
|
|
|
|
|
|
|
|
case actions.UPDATE_MATRIX:
|
|
|
|
return update(state, {
|
|
|
|
objectsById: { [action.id]: { transform: { $set: action.transform } } }
|
|
|
|
});
|
|
|
|
|
|
|
|
default:
|
|
|
|
return state;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
export default undoable(sketcherReducer, {
|
|
|
|
filter: undoFilter,
|
|
|
|
initTypes: []
|
|
|
|
// debug: true
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
function updateMenus(state, action) {
|
|
|
|
return {
|
|
|
|
...state,
|
|
|
|
menus: menusReducer(state.menus, action)
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
export function getD2ActiveShape(state) {
|
|
|
|
return getActive2D(state);
|
|
|
|
}
|
|
|
|
|
|
|
|
export function isEmpty(state) {
|
|
|
|
return Object.keys(state.sketcher.present.objectsById).length === 0;
|
|
|
|
}
|