Skip to content

Commit f0bf8c4

Browse files
remo5000ning-y
authored andcommitted
Add support for cruves (#217)
* Add most externals * Change clear() -> clear_viewport() This is a clear (lol) clash between the browser's clear() function, that removes all console output * Make getReadyWebGLForCanvas reset canvas Now, all init scripts just call that function. * Move initRuneBuffer to getReadyWebGLForCanvas * Remove init files We shall use a change in externals to decide this * Remove init files from index script * Add renderMode property * Diversify mock libraries Using all 4 external libraries available, and with the renderMode option * Add renderMode param to components and containers * Fix container imports and args Application (URL parsing) does not support library yet so it does not need to use the renderMode param. * Add renderMode argument for clearContext action * Refactor externals definitions - Separated 2d and 3d runes - Nicer names * Change clearContext usage in saga - Use null for things that should not affect clearContext - Generate a renderMode for SELECT_PLAYGROUND_EXTERNAL - Add a takeAll for CLEAR_CONTEXT that gets the canvas ready * Add documentation for saga * Format and update tests * Move externals definitions to a new file * Fix enum and import * Change renderMode -> externalLibraryName in usage components and containers * Change clearContext action definition * Update mock assessmentAPI * Fix import order * Change clearContext usage and CLEAR_CONTEXT saga To use the correct arguments, and swtich case for the ExternalLibraryNames * Remove shallow check for assessment * Add documentation for clearContext * Fix mock externals not loading * Change update method for content Workspaces i.e AssessmentWorkspace and GradingWorkspace. We depend on the componentDidUpdate being triggered, which is ensured by componentDidMount. This is because multiple dispatches one componentDidMount/componentDidUpdate does not work * Format files * Add delay for mock backend calls * Fix import order From rebase * Simplify loading and resetting logic for workspace This was causing some weird behaviour, but I think now the logic is simplier and it works better * Fix mock grading being passed as an object * Format files * Move ExternalLibraryName/ExternalLibraryNames * Format reducer * Remove delay
1 parent 97268b8 commit f0bf8c4

File tree

22 files changed

+355
-137
lines changed

22 files changed

+355
-137
lines changed

public/externalLibs/graphics/webGLcurve.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ function generateCurve(scaleMode, drawMode, numPoints, func, isFullView) {
7070
} else {
7171
// do nothing for normal situations
7272
}
73-
clear();
73+
clear_viewport();
7474
gl.uniformMatrix4fv(u_transformMatrix, false, transMat);
7575
drawCurve(drawMode, curvePosArray);
7676
return new ShapeDrawn();

public/externalLibs/graphics/webGLgraphics.js

Lines changed: 40 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,7 @@ var normalShaderProgram; // the default shader program
188188
var vertexBuffer;
189189
var vertexPositionAttribute; // location of a_position
190190
var colorAttribute; // location of a_color
191+
var canvas; // the <canvas> object that is used to display webGL output
191192

192193
// rune 2d and 3d
193194
var instance_ext; // ANGLE_instanced_arrays extension
@@ -245,15 +246,48 @@ function open_pixmap(name, horiz, vert, aa_off) {
245246
return canvas;
246247
}
247248

248-
function getReadyWebGLForCanvas(mode, canvas) {
249+
/**
250+
* Creates a <canvas> object, or resets it if it exists.
251+
*
252+
* Post-condition: canvas is defined as the selected <canvas>
253+
* object in the document.
254+
*/
255+
function resetCanvas() {
256+
canvas = document.querySelector('.rune-canvas');
257+
if (!canvas) {
258+
canvas = document.createElement('canvas');
259+
canvas.setAttribute('width', 512);
260+
canvas.setAttribute('height', 512);
261+
canvas.className = 'rune-canvas';
262+
canvas.hidden = true;
263+
document.body.appendChild(canvas);
264+
} else {
265+
canvas.parentNode.removeChild(canvas);
266+
resetCanvas();
267+
}
268+
}
269+
270+
/**
271+
* Gets the WebGL object (gl) ready for usage. Use this
272+
* to reset the mode of rendering i.e to change from 2d to 3d runes.
273+
*
274+
* Post-condition: gl is non-null, uses an appropriate
275+
* program and has an appropriate initialized state
276+
* for mode-specific rendering (e.g props for 3d render).
277+
*
278+
* @param mode a string -- '2d'/'3d'/'curve' that is the usage of
279+
* the gl object.
280+
*/
281+
function getReadyWebGLForCanvas(mode) {
282+
resetCanvas();
249283
// Get the rendering context for WebGL
250284
gl = initWebGL(canvas);
251285
if (gl) {
252286
gl.clearColor(1.0, 1.0, 1.0, 1.0); // Set clear color to white, fully opaque
253287
gl.enable(gl.DEPTH_TEST); // Enable depth testing
254288
gl.depthFunc(gl.LEQUAL); // Near things obscure far things
255289
// Clear the color as well as the depth buffer.
256-
clear();
290+
clear_viewport();
257291

258292
//TODO: Revise this, it seems unnecessary
259293
// Align the drawable canvas in the middle
@@ -274,6 +308,7 @@ function getReadyWebGLForCanvas(mode, canvas) {
274308
// rune-specific operations
275309
if (mode === '2d' || mode === '3d') {
276310
initRuneCommon();
311+
initRuneBuffer(vertices, indices);
277312
// rune-3d-specific operations
278313
if (mode === '3d') {
279314
initRune3d();
@@ -298,7 +333,7 @@ function getReadyWebGL(mode, name, horiz, vert, aa_off) {
298333
gl.enable(gl.DEPTH_TEST); // Enable depth testing
299334
gl.depthFunc(gl.LEQUAL); // Near things obscure far things
300335
// Clear the color as well as the depth buffer.
301-
clear();
336+
clear_viewport();
302337

303338
//TODO: Revise this, it seems unnecessary
304339
// Align the drawable canvas in the middle
@@ -491,11 +526,11 @@ function initFramebufferObject() {
491526

492527
function clearFramebuffer(framebuffer) {
493528
gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffer);
494-
clear();
529+
clear_viewport();
495530
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
496531
}
497532

498-
function clear() {
533+
function clear_viewport() {
499534
if (!gl) {
500535
throw new Error(
501536
'Please activate the Canvas component by clicking it in the sidebar'
@@ -508,8 +543,6 @@ function clear() {
508543
}
509544
}
510545

511-
var clear_viewport = clear; // firefox console already has function clear
512-
513546
//---------------------Rune 2d and 3d functions---------------------
514547
function initRuneCommon() {
515548
// set up attribute locations

public/externalLibs/graphics/webGLinit2D.js

Lines changed: 0 additions & 11 deletions
This file was deleted.

public/externalLibs/graphics/webGLinit3D.js

Lines changed: 0 additions & 11 deletions
This file was deleted.

public/externalLibs/graphics/webGLinitCurve.js

Lines changed: 0 additions & 10 deletions
This file was deleted.

public/externalLibs/graphics/webGLrune.js

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -394,14 +394,14 @@ function drawWithWebGL(flattened_shape_list, drawFunction) {
394394
}
395395

396396
function show(shape) {
397-
clear();
397+
clear_viewport();
398398
var flattened_shape_list = generateFlattenedShapeList(shape);
399399
drawWithWebGL(flattened_shape_list, drawRune);
400400
return new ShapeDrawn();
401401
}
402402

403403
function anaglyph(shape) {
404-
clear();
404+
clear_viewport();
405405
clearAnaglyphFramebuffer();
406406
var flattened_shape_list = generateFlattenedShapeList(shape);
407407
drawWithWebGL(flattened_shape_list, drawAnaglyph);
@@ -410,7 +410,7 @@ function anaglyph(shape) {
410410

411411
var hollusionTimeout;
412412
function hollusion(shape, num) {
413-
clear();
413+
clear_viewport();
414414
var num = num > 3 ? num : 3;
415415
var flattened_shape_list = generateFlattenedShapeList(shape);
416416
var frame_list = [];
@@ -443,7 +443,7 @@ function hollusion(shape, num) {
443443
gl.finish();
444444
copy_viewport(gl.canvas, frame);
445445
frame_list.push(frame);
446-
clear();
446+
clear_viewport();
447447
}
448448
for (var i = frame_list.length - 2; i > 0; i--) {
449449
frame_list.push(frame_list[i]);
@@ -464,7 +464,7 @@ function clearHollusion() {
464464
}
465465

466466
function stereogram(shape) {
467-
clear();
467+
clear_viewport();
468468
var flattened_shape_list = generateFlattenedShapeList(shape);
469469
var depth_map = open_pixmap('depth_map', viewport_size, viewport_size, true);
470470
// draw the depth map

public/externalLibs/index.js

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,18 +16,20 @@ function dynamicallyLoadScript(url) {
1616
*/
1717
function loadLibs() {
1818
const files = [
19+
// list library
1920
'/externalLibs/list.js',
21+
// sound
2022
'/externalLibs/sound/sounds.js',
2123
'/externalLibs/sound/soundToneMatrix.js',
2224
'/externalLibs/sound/riffwave.js',
25+
// graphics
2326
'/externalLibs/graphics/gl-matrix.js',
24-
'/externalLibs/graphics/webGLcurve.js',
25-
'/externalLibs/graphics/webGLgraphics.js',
2627
'/externalLibs/graphics/webGLhi_graph.js',
27-
'/externalLibs/graphics/webGLinitCurve.js',
28+
'/externalLibs/graphics/webGLhi_graph_ce.js',
29+
'/externalLibs/graphics/webGLgraphics.js',
30+
'/externalLibs/graphics/webGLcurve.js',
2831
'/externalLibs/graphics/webGLrune.js',
29-
'/externalLibs/graphics/webGLinit2D.js',
30-
'/externalLibs/graphics/webGLinit3D.js',
32+
// list visualizer
3133
'/externalLibs/visualizer/KineticJS.js',
3234
'/externalLibs/visualizer/visualizer.js',
3335
];
@@ -37,5 +39,4 @@ function loadLibs() {
3739
}
3840
}
3941

40-
// loadLibs(dependencies);
4142
loadLibs();

src/actions/workspaces.ts

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
import { ActionCreator } from 'redux'
2+
3+
import { ExternalLibraryName } from '../components/assessment/assessmentShape'
24
import * as actionTypes from './actionTypes'
35

46
/**
@@ -88,16 +90,26 @@ export const playgroundExternalSelect: ActionCreator<actionTypes.IAction> = (
8890
}
8991
})
9092

93+
/**
94+
* Clears the js-slang Context at a specified workspace location.
95+
*
96+
* @param chapter the SICP chapter for the context to be set in
97+
* @param externals a list of symbols to be exposed from the global scope
98+
* @param externalLibraryName the name of the external library used
99+
* @param workspaceLocation the location of the workspace
100+
*/
91101
export const clearContext = (
92102
chapter: number,
93103
externals: string[],
104+
externalLibraryName: ExternalLibraryName,
94105
workspaceLocation: WorkspaceLocation
95106
) => ({
96107
type: actionTypes.CLEAR_CONTEXT,
97108
payload: {
98-
workspaceLocation,
99109
chapter,
100-
externals
110+
externals,
111+
externalLibraryName,
112+
workspaceLocation
101113
}
102114
})
103115

src/components/academy/grading/GradingWorkspace.tsx

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { NonIdealState, Spinner, Text } from '@blueprintjs/core'
22
import { IconNames } from '@blueprintjs/icons'
33
import * as React from 'react'
44

5+
import { ExternalLibraryName } from '../../../components/assessment/assessmentShape'
56
import GradingEditor from '../../../containers/academy/grading/GradingEditorContainer'
67
import { InterpreterOutput } from '../../../reducers/states'
78
import { history } from '../../../utils/history'
@@ -41,7 +42,11 @@ export type DispatchProps = {
4142
handleBrowseHistoryUp: () => void
4243
handleChangeActiveTab: (activeTab: number) => void
4344
handleChapterSelect: (chapter: any, changeEvent: any) => void
44-
handleClearContext: (chapter: number, externals: string[]) => void
45+
handleClearContext: (
46+
chapter: number,
47+
externals: string[],
48+
externalLibraryName: ExternalLibraryName
49+
) => void
4550
handleEditorEval: () => void
4651
handleEditorValueChange: (val: string) => void
4752
handleEditorWidthChange: (widthChange: number) => void
@@ -56,11 +61,24 @@ export type DispatchProps = {
5661
}
5762

5863
class GradingWorkspace extends React.Component<GradingWorkspaceProps> {
64+
/**
65+
* First, check for a need to reset the workspace,
66+
* then fetch the grading. This works because a change in
67+
* submissionId or questionId results in a navigation, causing
68+
* this component to be mounted again. The handleGradingFetch
69+
* occurs after the call to checkWorkspaceReset finishes.
70+
*/
5971
public componentDidMount() {
6072
this.checkWorkspaceReset(this.props)
6173
this.props.handleGradingFetch(this.props.submissionId)
6274
}
6375

76+
/**
77+
* After the Grading is fetched, there is a check for wether the
78+
* workspace needs to be udpated (a change in submissionId or questionId)
79+
*/
80+
public componentDidUpdate() {}
81+
6482
public render() {
6583
if (this.props.grading === undefined) {
6684
return (
@@ -133,10 +151,11 @@ class GradingWorkspace extends React.Component<GradingWorkspaceProps> {
133151
this.props.storedQuestionId !== questionId
134152
) {
135153
const chapter = this.props.grading[questionId].question.library.chapter
154+
const externalName = this.props.grading[questionId].question.library.externalLibraryName
136155
const externals = this.props.grading[questionId].question.library.externals
137156
this.props.handleUpdateCurrentSubmissionId(submissionId, questionId)
138157
this.props.handleResetWorkspace()
139-
this.props.handleClearContext(chapter, externals)
158+
this.props.handleClearContext(chapter, externals, externalName)
140159
}
141160
}
142161

src/components/assessment/AssessmentWorkspace.tsx

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import Workspace, { WorkspaceProps } from '../workspace'
1010
import { ControlBarProps } from '../workspace/ControlBar'
1111
import { SideContentProps } from '../workspace/side-content'
1212
import {
13+
ExternalLibraryName,
1314
IAssessment,
1415
IMCQQuestion,
1516
IProgrammingQuestion,
@@ -44,7 +45,11 @@ export type DispatchProps = {
4445
handleBrowseHistoryUp: () => void
4546
handleChangeActiveTab: (activeTab: number) => void
4647
handleChapterSelect: (chapter: any, changeEvent: any) => void
47-
handleClearContext: (chapter: number, externals: string[]) => void
48+
handleClearContext: (
49+
chapter: number,
50+
externals: string[],
51+
externalLibraryName: ExternalLibraryName
52+
) => void
4853
handleEditorEval: () => void
4954
handleEditorValueChange: (val: string) => void
5055
handleEditorWidthChange: (widthChange: number) => void
@@ -63,9 +68,15 @@ class AssessmentWorkspace extends React.Component<
6368
> {
6469
public state = { showOverlay: false }
6570

71+
/**
72+
* First, check for a need to reset the workspace,
73+
* then fetch the assessment. This works because a change in
74+
* assessmentId or questionId results in a navigation, causing
75+
* this component to be mounted again. The handleAssessmentFetch
76+
* occurs after the call to checkWorkspaceReset finishes.
77+
*/
6678
public componentDidMount() {
6779
this.checkWorkspaceReset(this.props)
68-
/* Load assessment if it isn't passed as a prop. */
6980
this.props.handleAssessmentFetch(this.props.assessmentId)
7081
if (this.props.questionId === 0) {
7182
this.setState({ showOverlay: true })
@@ -158,10 +169,11 @@ class AssessmentWorkspace extends React.Component<
158169
this.props.storedQuestionId !== questionId
159170
) {
160171
const chapter = this.props.assessment.questions[questionId].library.chapter
172+
const externalName = this.props.assessment.questions[questionId].library.externalLibraryName
161173
const externals = this.props.assessment.questions[questionId].library.externals
162174
this.props.handleUpdateCurrentAssessmentId(assessmentId, questionId)
163175
this.props.handleResetWorkspace()
164-
this.props.handleClearContext(chapter, externals)
176+
this.props.handleClearContext(chapter, externals, externalName)
165177
}
166178
}
167179

0 commit comments

Comments
 (0)