From caf08ee32d901495df1e4d8563d12828f458a563 Mon Sep 17 00:00:00 2001 From: HF Date: Wed, 22 Jan 2020 15:34:46 +0100 Subject: [PATCH] Add 3d voxel canvas Add Canvas Selection Menu Improve Rendering Move ChunkRGB into seperate file --- public/preview0.png | Bin 0 -> 26306 bytes public/preview1.png | Bin 0 -> 24651 bytes public/preview2.png | Bin 0 -> 12581 bytes public/voxeltest.html | 21 - src/actions/index.js | 111 +- src/actions/types.js | 3 +- src/canvases.json | 55 +- src/client.js | 241 +- src/components/App.jsx | 38 +- src/components/CanvasItem.jsx | 105 + src/components/CanvasSelectModal.jsx | 53 + src/components/CanvasSwitchButton.jsx | 21 +- src/components/CoordinatesBox.jsx | 18 +- src/components/Menu.jsx | 2 - src/components/ModalRoot.jsx | 2 + src/components/NotifyBox.jsx | 11 +- src/components/UI.jsx | 42 + src/components/VoxelButton.jsx | 24 - src/controls/OrbitControls.js | 1164 --------- src/controls/PixelPainterControls.js | 210 ++ src/controls/VoxelPainterControls.js | 2200 ++++++++--------- src/controls/keypress.js | 37 + src/core/Image.js | 25 +- src/core/constants.js | 3 + src/core/draw.js | 44 +- src/core/mail.js | 2 +- src/core/tilesBackup.js | 10 +- src/core/tileserver.js | 28 +- src/core/utils.js | 81 +- src/data/models/RedisCanvas.js | 21 +- src/reducers/canvas.js | 153 +- src/reducers/modal.js | 1 + src/routes/admintools.js | 5 + src/routes/api/pixel.js | 35 +- src/routes/tiles.js | 26 +- src/socket/APISocketServer.js | 24 +- src/socket/packets/PixelUpdate.js | 7 +- src/store/audio.js | 65 +- src/store/notifications.js | 1 + src/store/promise.js | 1 + src/store/rendererHook.js | 34 +- src/store/title.js | 21 +- src/ui/ChunkLoader2D.js | 201 ++ src/ui/ChunkRGB.js | 29 +- src/ui/PixelNotify.js | 11 +- src/ui/{Renderer.js => Renderer2D.js} | 192 +- src/ui/Renderer3D.js | 279 +++ src/ui/ads.js | 3 +- src/ui/keypress.js | 69 - src/ui/loadImage.js | 8 +- ...{renderelements.js => render2Delements.js} | 6 +- src/ui/renderer.js | 39 + src/voxel.js | 204 -- src/voxelSA.js | 199 -- 54 files changed, 2499 insertions(+), 3686 deletions(-) create mode 100644 public/preview0.png create mode 100644 public/preview1.png create mode 100644 public/preview2.png delete mode 100644 public/voxeltest.html create mode 100644 src/components/CanvasItem.jsx create mode 100644 src/components/CanvasSelectModal.jsx create mode 100644 src/components/UI.jsx delete mode 100644 src/components/VoxelButton.jsx delete mode 100644 src/controls/OrbitControls.js create mode 100644 src/controls/PixelPainterControls.js create mode 100644 src/controls/keypress.js create mode 100644 src/ui/ChunkLoader2D.js rename src/ui/{Renderer.js => Renderer2D.js} (79%) create mode 100644 src/ui/Renderer3D.js delete mode 100644 src/ui/keypress.js rename src/ui/{renderelements.js => render2Delements.js} (91%) create mode 100644 src/ui/renderer.js delete mode 100644 src/voxel.js delete mode 100644 src/voxelSA.js diff --git a/public/preview0.png b/public/preview0.png new file mode 100644 index 0000000000000000000000000000000000000000..493617797d8bee60a5181ce7dee628ff1ad222d3 GIT binary patch literal 26306 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

M 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 S#jlM30000eUj5e{s#Q7VPhh%y%MIQC@82u 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 literal 0 HcmV?d00001 diff --git a/public/voxeltest.html b/public/voxeltest.html deleted file mode 100644 index e98022e..0000000 --- a/public/voxeltest.html +++ /dev/null @@ -1,21 +0,0 @@ - - - - three.js webgl - interactive - voxel painter - - - - - - - - - diff --git a/src/actions/index.js b/src/actions/index.js index d053f11..227c2ed 100644 --- a/src/actions/index.js +++ b/src/actions/index.js @@ -8,12 +8,6 @@ import type { import type { Cell } from '../core/Cell'; import type { ColorIndex } from '../core/Palette'; -import { loadImage } from '../ui/loadImage'; -import { - getColorIndexOfPixel, -} from '../core/utils'; - - export function sweetAlert( title: string, text: string, @@ -228,7 +222,6 @@ export function requestPlacePixel( y, clr: color, token, - a: x + y + 8, }); dispatch(setPlaceAllowed(false)); @@ -295,9 +288,7 @@ export function tryPlacePixel( ? state.gui.selectedColor : color; - if (getColorIndexOfPixel(getState(), coordinates) !== selectedColor) { - dispatch(requestPlacePixel(canvasId, coordinates, selectedColor)); - } + dispatch(requestPlacePixel(canvasId, coordinates, selectedColor)); }; } @@ -376,37 +367,23 @@ export function zoomOut(zoompoint): ThunkAction { }; } -function requestBigChunk(center: Cell): Action { +export function requestBigChunk(center: Cell): Action { return { type: 'REQUEST_BIG_CHUNK', center, }; } -function receiveBigChunk( +export function receiveBigChunk( center: Cell, - arrayBuffer: ArrayBuffer, ): Action { return { type: 'RECEIVE_BIG_CHUNK', center, - arrayBuffer, }; } -function receiveImageTile( - center: Cell, - tile: Image, -): Action { - return { - type: 'RECEIVE_IMAGE_TILE', - center, - tile, - }; -} - - -function receiveBigChunkFailure(center: Cell, error: Error): Action { +export function receiveBigChunkFailure(center: Cell, error: Error): Action { return { type: 'RECEIVE_BIG_CHUNK_FAILURE', center, @@ -414,74 +391,6 @@ function receiveBigChunkFailure(center: Cell, error: Error): Action { }; } -export function fetchTile(canvasId, center: Cell): PromiseAction { - const [cz, cx, cy] = center; - - return async (dispatch) => { - dispatch(requestBigChunk(center)); - try { - const url = `/tiles/${canvasId}/${cz}/${cx}/${cy}.png`; - const img = await loadImage(url); - dispatch(receiveImageTile(center, img)); - } catch (error) { - dispatch(receiveBigChunkFailure(center, error)); - } - }; -} - -export function fetchHistoricalChunk( - canvasId: number, - center: Cell, - historicalDate: string, - historicalTime: string, -): PromiseAction { - const [cx, cy] = center; - - return async (dispatch) => { - let url = `${window.backupurl}/${historicalDate}/`; - let zkey; - if (historicalTime) { - // incremential tiles - zkey = `${historicalDate}${historicalTime}`; - url += `${canvasId}/${historicalTime}/${cx}/${cy}.png`; - } else { - // full tiles - zkey = historicalDate; - url += `${canvasId}/tiles/${cx}/${cy}.png`; - } - const keyValues = [zkey, cx, cy]; - dispatch(requestBigChunk(keyValues)); - try { - const img = await loadImage(url); - dispatch(receiveImageTile(keyValues, img)); - } catch (error) { - dispatch(receiveBigChunkFailure(keyValues, error)); - } - }; -} - -export function fetchChunk(canvasId, center: Cell): PromiseAction { - const [, cx, cy] = center; - - return async (dispatch) => { - dispatch(requestBigChunk(center)); - try { - const url = `/chunks/${canvasId}/${cx}/${cy}.bmp`; - const response = await fetch(url); - if (response.ok) { - const arrayBuffer = await response.arrayBuffer(); - dispatch(receiveBigChunk(center, arrayBuffer)); - } else { - const error = new Error('Network response was not ok.'); - dispatch(receiveBigChunkFailure(center, error)); - } - } catch (error) { - dispatch(receiveBigChunkFailure(center, error)); - } - }; -} - - export function receiveCoolDown( waitSeconds: number, ): Action { @@ -491,7 +400,6 @@ export function receiveCoolDown( }; } - export function receivePixelUpdate( i: number, j: number, @@ -678,6 +586,10 @@ export function showHelpModal(): Action { return showModal('HELP'); } +export function showCanvasSelectionModal(): Action { + return showModal('CANVAS_SELECTION'); +} + export function showChatModal(): Action { if (window.innerWidth > 604) { return toggleChatBox(); } return showModal('CHAT'); @@ -714,10 +626,3 @@ export function urlChange(): PromiseAction { dispatch(reloadUrl()); }; } - -export function switchCanvas(canvasId: number): PromiseAction { - return async (dispatch) => { - await dispatch(selectCanvas(canvasId)); - dispatch(onViewFinishChange()); - }; -} diff --git a/src/actions/types.js b/src/actions/types.js index 42341a1..f361427 100644 --- a/src/actions/types.js +++ b/src/actions/types.js @@ -41,8 +41,7 @@ export type Action = | { type: 'SET_VIEW_COORDINATES', view: Cell } | { type: 'SET_SCALE', scale: number, zoompoint: Cell } | { type: 'REQUEST_BIG_CHUNK', center: Cell } - | { type: 'RECEIVE_BIG_CHUNK', center: Cell, arrayBuffer: ArrayBuffer } - | { type: 'RECEIVE_IMAGE_TILE', center: Cell, tile: Image } + | { type: 'RECEIVE_BIG_CHUNK', center: Cell } | { type: 'RECEIVE_BIG_CHUNK_FAILURE', center: Cell, error: Error } | { type: 'RECEIVE_COOLDOWN', waitSeconds: number } | { type: 'RECEIVE_PIXEL_UPDATE', diff --git a/src/canvases.json b/src/canvases.json index 1ddf9b8..c6a3cf6 100644 --- a/src/canvases.json +++ b/src/canvases.json @@ -1,6 +1,7 @@ { "0": { "ident":"d", + "title": "Earth", "colors": [ [ 202, 227, 255 ], [ 255, 255, 255 ], @@ -41,10 +42,12 @@ "pcd" : 7000, "cds": 60000, "req": -1, - "sd": "2020-01-08" + "sd": "2020-01-08", + "desc": "Our main canvas, a huge map of the world. Place everywhere you like" }, "1": { "ident": "m", + "title": "Moon", "colors" : [ [ 49, 46, 47 ], [ 99, 92, 90 ], @@ -85,6 +88,54 @@ "pcd": 15000, "cds": 900000, "req": 8000, - "sd": "2020-01-08" + "sd": "2020-01-08", + "desc": "Moon canvas with a pastel tone palette and black background" + }, + "2": { + "ident":"v", + "title": "3D Canvas", + "colors": [ + [ 202, 227, 255 ], + [ 255, 255, 255 ], + [ 255, 255, 255 ], + [ 228, 228, 228 ], + [ 196, 196, 196 ], + [ 136, 136, 136 ], + [ 78, 78, 78 ], + [ 0, 0, 0 ], + [ 244, 179, 174 ], + [ 255, 167, 209 ], + [ 255, 84, 178 ], + [ 255, 101, 101 ], + [ 229, 0, 0 ], + [ 154, 0, 0 ], + [ 254, 164, 96 ], + [ 229, 149, 0 ], + [ 160, 106, 66 ], + [ 96, 64, 40 ], + [ 245, 223, 176 ], + [ 255, 248, 137 ], + [ 229, 217, 0 ], + [ 148, 224, 68 ], + [ 2, 190, 1 ], + [ 104, 131, 56 ], + [ 0, 101, 19 ], + [ 202, 227, 255 ], + [ 0, 211, 221 ], + [ 0, 131, 199 ], + [ 0, 0, 234 ], + [ 25, 25, 115 ], + [ 207, 110, 228 ], + [ 130, 0, 128 ] + ], + "alpha": 0, + "size": 1024, + "v": true, + "bcd": 2000, + "pcd" : 2000, + "cds": 60000, + "req": 0, + "sd": "2020-01-08", + "desc": "Test 3D canvas. Changes are not saved." } } diff --git a/src/client.js b/src/client.js index 4fd8bb0..483497b 100644 --- a/src/client.js +++ b/src/client.js @@ -4,208 +4,39 @@ import React from 'react'; import ReactDOM from 'react-dom'; import { Provider } from 'react-redux'; import fetch from 'isomorphic-fetch'; // TODO put in the beggining with webpack! -import Hammer from 'hammerjs'; import './components/font.css'; +// import initAds, { requestAds } from './ui/ads'; +import onKeyPress from './controls/keypress'; import { - screenToWorld, - getColorIndexOfPixel, -} from './core/utils'; - -import type { State } from './reducers'; -import initAds, { requestAds } from './ui/ads'; -import { - tryPlacePixel, - setHover, - unsetHover, - setViewCoordinates, - setScale, - zoomIn, - zoomOut, receivePixelUpdate, receiveCoolDown, fetchMe, fetchStats, initTimer, urlChange, - onViewFinishChange, receiveOnline, receiveChatMessage, receiveChatHistory, - selectColor, } from './actions'; import store from './ui/store'; -import onKeyPress from './ui/keypress'; import App from './components/App'; -import renderer from './ui/Renderer'; +import { initRenderer, getRenderer } from './ui/renderer'; import ProtocolClient from './socket/ProtocolClient'; -window.addEventListener('keydown', onKeyPress, false); - - -function initViewport() { - const canvas = document.getElementById('gameWindow'); - - const viewport = canvas; - viewport.width = window.innerWidth; - viewport.height = window.innerHeight; - - // track hover - viewport.onmousemove = ({ clientX, clientY }: MouseEvent) => { - store.dispatch(setHover([clientX, clientY])); - }; - viewport.onmouseout = () => { - store.dispatch(unsetHover()); - }; - viewport.onwheel = ({ deltaY }: WheelEvent) => { - const state = store.getState(); - const { hover } = state.gui; - let zoompoint = null; - if (hover) { - zoompoint = screenToWorld(state, viewport, hover); - } - if (deltaY < 0) { - store.dispatch(zoomIn(zoompoint)); - } - if (deltaY > 0) { - store.dispatch(zoomOut(zoompoint)); - } - store.dispatch(onViewFinishChange()); - }; - viewport.onauxclick = ({ which, clientX, clientY }: MouseEvent) => { - // middle mouse button - if (which !== 2) { - return; - } - const state = store.getState(); - if (state.canvas.scale < 3) { - return; - } - const coords = screenToWorld(state, viewport, [clientX, clientY]); - const clrIndex = getColorIndexOfPixel(state, coords); - if (clrIndex === null) { - return; - } - store.dispatch(selectColor(clrIndex)); - }; - - // fingers controls on touch - const hammertime = new Hammer(viewport); - hammertime.get('pan').set({ direction: Hammer.DIRECTION_ALL }); - hammertime.get('swipe').set({ direction: Hammer.DIRECTION_ALL }); - // Zoom-in Zoom-out in touch devices - hammertime.get('pinch').set({ enable: true }); - - hammertime.on('tap', ({ center }) => { - const state = store.getState(); - const { autoZoomIn } = state.gui; - const { placeAllowed } = state.user; - - const { - scale, - isHistoricalView, - } = state.canvas; - if (isHistoricalView) return; - - const { x, y } = center; - const cell = screenToWorld(state, viewport, [x, y]); - - if (autoZoomIn && scale < 8) { - store.dispatch(setViewCoordinates(cell)); - store.dispatch(setScale(12)); - return; - } - - // don't allow placing of pixel just on low zoomlevels - if (scale < 3) return; - - if (!placeAllowed) return; - - // dirty trick: to fetch only before multiple 3 AND on user action - // if (pixelsPlaced % 3 === 0) requestAds(); - - // TODO assert only one finger - store.dispatch(tryPlacePixel(cell)); - }); - - const initialState: State = store.getState(); - [window.lastPosX, window.lastPosY] = initialState.canvas.view; - let lastScale = initialState.canvas.scale; - hammertime.on( - 'panstart pinchstart pan pinch panend pinchend', - ({ - type, deltaX, deltaY, scale, - }) => { - viewport.style.cursor = 'move'; // like google maps - const { scale: viewportScale } = store.getState().canvas; - - // pinch start - if (type === 'pinchstart') { - store.dispatch(unsetHover()); - lastScale = viewportScale; - } - - // panstart - if (type === 'panstart') { - store.dispatch(unsetHover()); - const { view: initView } = store.getState().canvas; - [window.lastPosX, window.lastPosY] = initView; - } - - // pinch - if (type === 'pinch') { - store.dispatch(setScale(lastScale * scale)); - } - - // pan - store.dispatch(setViewCoordinates([ - window.lastPosX - (deltaX / viewportScale), - window.lastPosY - (deltaY / viewportScale), - ])); - - // pinch end - if (type === 'pinchend') { - lastScale = viewportScale; - } - - // panend - if (type === 'panend') { - store.dispatch(onViewFinishChange()); - const { view } = store.getState().canvas; - [window.lastPosX, window.lastPosY] = view; - viewport.style.cursor = 'auto'; - } - }, - ); - - return viewport; -} - - -document.addEventListener('DOMContentLoaded', () => { - ReactDOM.render( - - - , - document.getElementById('app'), - ); - - const viewport = initViewport(); - renderer.setViewport(viewport, store); +function init() { + initRenderer(store, false); ProtocolClient.on('pixelUpdate', ({ i, j, offset, color, }) => { store.dispatch(receivePixelUpdate(i, j, offset, color)); - // render updated pixel - renderer.renderPixel(i, j, offset, color); }); ProtocolClient.on('cooldownPacket', (waitSeconds) => { - console.log(`Received CoolDown ${waitSeconds}`); store.dispatch(receiveCoolDown(waitSeconds)); }); ProtocolClient.on('onlineCounter', ({ online }) => { @@ -221,55 +52,53 @@ document.addEventListener('DOMContentLoaded', () => { store.dispatch(fetchMe()); }); - window.addEventListener('resize', () => { - viewport.width = window.innerWidth; - viewport.height = window.innerHeight; - renderer.forceNextRender = true; - }); window.addEventListener('hashchange', () => { store.dispatch(urlChange()); }); - store.subscribe(() => { - // const state: State = store.getState(); - // this gets executed when store changes - }); - store.dispatch(initTimer()); - window.animationLoop = function animationLoop() { - renderer.render(viewport); - window.requestAnimationFrame(window.animationLoop); - } - window.animationLoop(); - window.store = store; - store.dispatch(fetchMe()); ProtocolClient.connect(); store.dispatch(fetchStats()); setInterval(() => { store.dispatch(fetchStats()); }, 300000); +} +init(); + +document.addEventListener('DOMContentLoaded', () => { + ReactDOM.render( + + + , + document.getElementById('app'), + ); + + document.addEventListener('keydown', onKeyPress, false); // garbage collection function runGC() { - const state: State = store.getState(); - const { chunks } = state.canvas; + const renderer = getRenderer(); - const curTime = Date.now(); - let cnt = 0; - chunks.forEach((value, key) => { - if (curTime > value.timestamp + 300000) { - cnt++; - const [z, i, j] = value.cell; - if (!renderer.isChunkInView(z, i, j)) { - if (value.isBasechunk) { - ProtocolClient.deRegisterChunk([i, j]); + const chunks = renderer.getAllChunks(); + if (chunks) { + const curTime = Date.now(); + let cnt = 0; + chunks.forEach((value, key) => { + if (curTime > value.timestamp + 300000) { + cnt++; + const [z, i, j] = value.cell; + if (!renderer.isChunkInView(z, i, j)) { + if (value.isBasechunk) { + ProtocolClient.deRegisterChunk([i, j]); + } + chunks.delete(key); } - chunks.delete(key); } - } - }); - console.log('Garbage collection cleaned', cnt, 'chunks'); + }); + // eslint-disable-next-line no-console + console.log('Garbage collection cleaned', cnt, 'chunks'); + } } setInterval(runGC, 300000); }); diff --git a/src/components/App.jsx b/src/components/App.jsx index c069e76..c391f15 100644 --- a/src/components/App.jsx +++ b/src/components/App.jsx @@ -4,32 +4,25 @@ */ import React from 'react'; -import { connect } from 'react-redux'; import { IconContext } from 'react-icons'; -import type { State } from '../reducers'; -import CoolDownBox from './CoolDownBox'; -import NotifyBox from './NotifyBox'; import CoordinatesBox from './CoordinatesBox'; -import GlobeButton from './GlobeButton'; import CanvasSwitchButton from './CanvasSwitchButton'; import OnlineBox from './OnlineBox'; -import PalselButton from './PalselButton'; import ChatButton from './ChatButton'; -import Palette from './Palette'; import ChatBox from './ChatBox'; import Menu from './Menu'; +import UI from './UI'; import ReCaptcha from './ReCaptcha'; import ExpandMenuButton from './ExpandMenuButton'; import ModalRoot from './ModalRoot'; -import HistorySelect from './HistorySelect'; import baseCss from './base.tcss'; -const App = ({ isHistoricalView }) => ( +const App = () => (

+ {/* eslint-disable-next-line react/no-danger */}