diff --git a/source/asdf-ext.lisp b/source/asdf-ext.lisp index 935a918..a0267dc 100644 --- a/source/asdf-ext.lisp +++ b/source/asdf-ext.lisp @@ -1,7 +1,3 @@ (in-package :asdf) (defclass clog-file (asdf:doc-file) ((type :initform "clog"))) - - - - diff --git a/source/clog-canvas.lisp b/source/clog-canvas.lisp index e2d48e4..f91761d 100644 --- a/source/clog-canvas.lisp +++ b/source/clog-canvas.lisp @@ -57,10 +57,9 @@ (defmethod create-context2d ((obj clog-canvas)) (let ((web-id (clog-connection:generate-id))) - (clog-connection:execute (connection-id obj) - (format nil "clog['~A']=clog['~A'].getContext('2d')" - web-id - (html-id obj))) + (js-execute obj (format nil "clog['~A']=clog['~A'].getContext('2d')" + web-id + (html-id obj))) (make-instance 'clog-context2d :connection-id (connection-id obj) :html-id web-id))) diff --git a/source/clog-webgl.lisp b/source/clog-webgl.lisp index 070a23a..37904ce 100644 --- a/source/clog-webgl.lisp +++ b/source/clog-webgl.lisp @@ -6,7 +6,59 @@ ;;;; clog-webgl.lisp ;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -(cl:in-package :clog) +(mgl-pax:define-package :clog-webgl + (:documentation "CLOG-WEBGL bindings to WebGL") + (:use #:cl #:parse-float #:clog #:mgl-pax)) + +(cl:in-package :clog-webgl) + +(defsection @clog-webgl (:title "CLOG WebGL Objects") + "CLOG-WebGL - Class for CLOG WebGL objects" + (clog-webgl class) + (create-webgl generic-function) + (compile-shader-source generic-function) + (compile-webgl-program generic-function) + (clear-color generic-function) + (clear-webgl generic-function) + (viewport generic-function) + (enable-vertex-attribute-array generic-function) + (vertex-attribute-pointer generic-function) + (draw-arrays generic-function) + + "CLOG-WebGL-Shader - Class for CLOG WebGL-Shader objects" + (clog-webgl-shader class) + (create-shader generic-function) + + (shader-source generic-function) + (shader-parameter generic-function) + (shader-info-log generic-function) + (compile-shader generic-function) + (delete-shader generic-function) + + "CLOG-WebGL-Program - Class for CLOG WebGL-Program objects" + (clog-webgl-program class) + (create-program generic-function) + + (attach-shader generic-function) + (program-parameter generic-function) + (attribute-location generic-function) + (program-info-log generic-function) + (link-program generic-function) + (use-program generic-function) + (delete-program generic-function) + + "CLOG-WebGL-Buffer - Class for CLOG WebGL-Buffer objects" + (clog-webgl-buffer class) + (create-webgl-buffer generic-function) + (bind-buffer generic-function) + (buffer-data generic-function) + (delete-buffer generic-function) + + "CLOG-WebGL-Vertex-Array - Class for CLOG WebGL-Vertex-Array objects" + (clog-vertex-array class) + (create-vertex-array generic-function) + (bind-vertex-array generic-function) + (delete-vertex-array generic-function)) ;; Use clog-canvas to create the html element and then use clog-webgl ;; to obtain the WebGL2 context @@ -27,11 +79,251 @@ (defmethod create-webgl ((obj clog-canvas)) (let ((web-id (clog-connection:generate-id))) - (clog-connection:execute (connection-id obj) - (format nil "clog['~A']=clog['~A'].getContext('webgl2')" - web-id - (html-id obj))) - (make-instance 'clog-context2d - :connection-id (connection-id obj) + (js-execute obj (format nil "clog['~A']=clog['~A'].getContext('webgl2')" + web-id + (html-id obj))) + (make-instance 'clog-webgl + :connection-id (clog::connection-id obj) :html-id web-id))) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Implementation - clog-webgl-shader +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(defclass clog-webgl-shader (clog-obj) + ((gl :accessor gl :initarg :clog-webgl))) + +(defgeneric create-shader (clog-webgl glenum-type) + (:documentation "Create a clog-webgl-shader for type :GLENUM. +See https://github.com/KhronosGroup/WebGL/blob/main/specs/latest/2.0/webgl2.idl +For :GLENUM values")) + +(defmethod create-shader ((obj clog-webgl) glenum-type) + (let ((web-id (clog-connection:generate-id))) + (js-execute obj (format nil "clog['~A']=~A.createShader(~A.~A)" + web-id + (script-id obj) (script-id obj) glenum-type)) + (make-instance 'clog-webgl-shader + :connection-id (clog::connection-id obj) + :html-id web-id + :clog-webgl obj))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Properties - clog-webgl-shader +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(defmethod (setf shader-source) (source (obj clog-webgl-shader)) + (execute (gl obj) (format nil "shaderSource(~A, '~A')" + (script-id obj) + (escape-string source))) + source) + +(defmethod shader-parameter ((obj clog-webgl-shader) glenum-param) + (query (gl obj) (format nil "getShaderParameter(~A, ~A.~A)" + (script-id obj) + (script-id (gl obj)) glenum-param))) + +(defmethod shader-info-log ((obj clog-webgl-shader)) + (query (gl obj) (format nil "getShaderInfoLog(~A)" + (script-id obj)))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Methods - clog-webgl-shader +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(defmethod compile-shader ((obj clog-webgl-shader)) + (execute (gl obj) (format nil "compileShader(~A)" + (script-id obj)))) + +(defmethod delete-shader ((obj clog-webgl-shader)) + (execute (gl obj) (format nil "deleteShader(~A)" + (script-id obj)))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Implementation - clog-webgl-program +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(defclass clog-webgl-program (clog-obj) + ((gl :accessor gl :initarg :clog-webgl))) + +(defgeneric create-program (clog-webgl) + (:documentation "Create a clog-webgl-program")) + +(defmethod create-program ((obj clog-webgl)) + (let ((web-id (clog-connection:generate-id))) + (js-execute obj (format nil "clog['~A']=~A.createProgram()" + web-id + (script-id obj))) + (make-instance 'clog-webgl-program + :connection-id (clog::connection-id obj) + :html-id web-id + :clog-webgl obj))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Parameters - clog-webgl-program +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(defmethod program-parameter ((obj clog-webgl-program) glenum-param) + (query (gl obj) (format nil "getProgramParameter(~A, ~A.~A)" + (script-id obj) + (script-id (gl obj)) glenum-param))) + +(defmethod attribute-location ((obj clog-webgl-program) name) + (query (gl obj) (format nil "getAttribLocation(~A, '~A')" + (script-id obj) name))) + +(defmethod program-info-log ((obj clog-webgl-program)) + (query (gl obj) (format nil "getProgramInfoLog(~A)" + (script-id obj)))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Methods - clog-webgl-program +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(defmethod attach-shader ((obj clog-webgl-program) (shader clog-webgl-shader)) + (execute (gl obj) (format nil "attachShader(~A, ~A)" + (script-id obj) + (script-id shader)))) + +(defmethod link-program ((obj clog-webgl-program)) + (execute (gl obj) (format nil "linkProgram(~A)" (script-id obj)))) + +(defmethod use-program ((obj clog-webgl-program)) + (execute (gl obj) (format nil "useProgram(~A)" (script-id obj)))) + +(defmethod delete-program ((obj clog-webgl-program)) + (execute (gl obj) (format nil "deleteProgram(~A)" + (script-id obj)))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Methdods - clog-webgl +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(defmethod clear-color ((obj clog-webgl) red green blue alpha) + (execute obj (format nil "clearColor(~A,~A,~A,~A)" + red green blue alpha))) + +(defmethod clear-webgl ((obj clog-webgl) glenum-mask) + (execute obj (format nil "clear(~A.~A)" + (script-id obj) + glenum-mask))) + +(defmethod viewport ((obj clog-webgl) x y width height) + (execute obj (format nil "viewport(~A,~A,~A,~A)" + x y width height))) + +(defmethod draw-arrays ((obj clog-webgl) primitive-type offset count) + (execute obj (format nil "drawArrays(~A.~A,~A,~A)" + (script-id obj) primitive-type + offset count))) + +(defmethod enable-vertex-attribute-array ((obj clog-webgl) attribute-location) + (execute obj (format nil "enableVertexAttribArray(~A)" + attribute-location))) + +(defmethod vertex-attribute-pointer ((obj clog-webgl) attribute-location size type normalize stride offset) + (execute obj (format nil "vertexAttribPointer(~A,~A,~A.~A,~A,~A,~A)" + attribute-location size (script-id obj) type + (p-true-js normalize) stride offset))) + +(defmethod compile-shader-source ((obj clog-webgl) glenum-type source) + (let ((shader (create-shader obj glenum-type))) + (setf (shader-source shader) source) + (compile-shader shader) + (let ((result (shader-parameter shader :COMPILE_STATUS))) + (cond ((js-true-p result) + shader) + (t + (setf result (shader-info-log shader)) + (delete-shader shader) + (error result)))))) + +(defmethod compile-webgl-program ((obj clog-webgl) vertex-shader fragment-shader) + (let ((program (create-program obj))) + (attach-shader program vertex-shader) + (attach-shader program fragment-shader) + (link-program program) + (let ((result (program-parameter program :LINK_STATUS))) + (cond ((js-true-p result) + program) + (t + (setf result (program-info-log program)) + (delete-program program) + (error result)))))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Implementation - clog-webgl-buffer +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(defclass clog-webgl-buffer (clog-obj) + ((gl :accessor gl :initarg :clog-webgl) + (gl-type :accessor gl-type :initarg :gl-type))) + +(defgeneric create-webgl-buffer (clog-webgl &key bind-type) + (:documentation "Create a clog-webgl-buffer")) + +(defmethod create-webgl-buffer ((obj clog-webgl) &key bind-type) + (let ((web-id (clog-connection:generate-id))) + (js-execute obj (format nil "clog['~A']=~A.createBuffer()" + web-id + (script-id obj))) + (let ((new-obj (make-instance 'clog-webgl-buffer + :connection-id (clog::connection-id obj) + :html-id web-id + :clog-webgl obj + :gl-type bind-type))) + (when bind-type + (bind-buffer new-obj bind-type)) + new-obj))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Methods - clog-webgl-buffer +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(defmethod bind-buffer ((obj clog-webgl-buffer) glenum-target) + (execute (gl obj) (format nil "bindBuffer(~A.~A,~A)" + (script-id (gl obj)) glenum-target + (script-id obj))) + (setf (gl-type obj) glenum-target)) + +(defmethod buffer-data ((obj clog-webgl-buffer) data-list data-type hint) + (execute (gl obj) (format nil "bufferData(~A.~A, new ~A([~{~A~^,~}]), ~A.~A)" + (script-id (gl obj)) (gl-type obj) + data-type data-list + (script-id (gl obj)) hint))) + +(defmethod delete-buffer ((obj clog-webgl-buffer)) + (execute (gl obj) (format nil "deleteBuffer(~A)" + (script-id obj)))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Implementation - clog-webgl-vertex-array +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(defclass clog-webgl-vertex-array (clog-obj) + ((gl :accessor gl :initarg :clog-webgl))) + +(defgeneric create-vertex-array (clog-webgl) + (:documentation "Create a clog-webgl-vertex-array")) + +(defmethod create-vertex-array ((obj clog-webgl)) + (let ((web-id (clog-connection:generate-id))) + (js-execute obj (format nil "clog['~A']=~A.createVertexArray()" + web-id + (script-id obj))) + (make-instance 'clog-webgl-vertex-array + :connection-id (clog::connection-id obj) + :html-id web-id + :clog-webgl obj))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Methods - clog-webgl-vertex-array +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(defmethod bind-vertex-array ((obj clog-webgl-vertex-array)) + (execute (gl obj) (format nil "bindVertexArray(~A)" + (script-id obj)))) + +(defmethod delete-vertex-array ((obj clog-webgl-vertex-array)) + (execute (gl obj) (format nil "deleteVertexArray(~A)" + (script-id obj)))) diff --git a/source/clog.lisp b/source/clog.lisp index 0ea52c0..2fb306b 100644 --- a/source/clog.lisp +++ b/source/clog.lisp @@ -770,11 +770,6 @@ embedded in a native template application.)" (canvas-save generic-function) (canvas-restore generic-function)) -(defsection @clog-webgl (:title "CLOG WebGL Objects") - "CLOG-WebGL - Class for CLOG WebGL objects" - (clog-webgl class) - (create-webgl generic-function)) - (defsection @clog-multimedia (:title "CLOG Multimedia Objects") "CLOG-Multimedia - Base Class for CLOG multimedia objects" (clog-multimedia class) diff --git a/tutorial/34-tutorial.lisp b/tutorial/34-tutorial.lisp new file mode 100644 index 0000000..095fff8 --- /dev/null +++ b/tutorial/34-tutorial.lisp @@ -0,0 +1,68 @@ +(defpackage #:clog-tut-34 + (:use #:cl #:clog #:clog-webgl) + (:export start-tutorial)) + +(in-package :clog-tut-34) + +;; example based on - https://webgl2fundamentals.org/webgl/lessons/webgl-fundamentals.html + +;; "#version 300 es" MUST BE THE VERY FIRST LINE OF YOUR SHADER. +;; No comments or blank lines are allowed before it +(defparameter *vertex-shader-source* "#version 300 es + +// an attribute is an input (in) to a vertex shader. +// It will receive data from a buffer +in vec4 a_position; + +// all shaders have a main function +void main() { + + // gl_Position is a special variable a vertex shader + // is responsible for setting + gl_Position = a_position; +}") + +(defparameter *fragment-shader-source* "#version 300 es + +// fragment shaders don't have a default precision so we need +// to pick one. highp is a good default. It means \"high precision\" +precision highp float; + +// we need to declare an output for the fragment shader +out vec4 outColor; + +void main() { + // Just set the output to a constant reddish-purple + outColor = vec4(1, 0, 0.5, 1); +}") + +(defun on-new-window (body) + (debug-mode body) + (setf (title (html-document body)) "Tutorial 34") + (let* ((canvas (create-canvas body :width 1000 :height 500)) + (gl (create-webgl canvas)) + (vertex-shader (compile-shader-source gl :VERTEX_SHADER *vertex-shader-source*)) + (fragment-shader (compile-shader-source gl :FRAGMENT_SHADER *fragment-shader-source*)) + (program (compile-webgl-program gl vertex-shader fragment-shader)) + (pos (attribute-location program "a_position")) + (pos-buffer (create-webgl-buffer gl)) + (vao (create-vertex-array gl))) + (bind-buffer pos-buffer :ARRAY_BUFFER) + (buffer-data pos-buffer `(0 0 + 0 0.5 + 0.7 0) + "Float32Array" :STATIC_DRAW) + (bind-vertex-array vao) + (enable-vertex-attribute-array gl pos) + (vertex-attribute-pointer gl pos 2 :FLOAT nil 0 0) + (viewport gl 0 0 (width canvas) (height canvas)) + (clear-color gl 0.0 0.0 0.0 1.0) + (clear-webgl gl :COLOR_BUFFER_BIT) + (use-program program) + (bind-vertex-array vao) + (draw-arrays gl :TRIANGLES 0 3))) + +(defun start-tutorial () + "Start turtorial." + (initialize 'on-new-window) + (open-browser))