0
Fork 0
mirror of https://github.com/penpot/penpot.git synced 2025-01-21 14:12:36 -05:00
This commit is contained in:
Aitor 2023-12-20 13:29:29 +01:00
parent e08e2bf64a
commit 6b50c17781
3 changed files with 108 additions and 43 deletions

View file

@ -3,6 +3,7 @@
(:require-macros [app.util.gl.macros :refer [slurp]])
(:require
["gl-matrix" :as glm]
[app.common.data.macros :as dm]
[app.common.math :as math]
[app.util.gl :as gl]
[cuerdas.core :as str]
@ -15,6 +16,7 @@
#_(def shaders (js/Map.))
(def programs (js/Map.))
(def program-actives (js/Map.))
#_(def textures (js/Map.))
#_(def framebuffers (js/Map.))
@ -53,6 +55,25 @@
:bool 7
:frame 8))
(defn get-object-border-radius-as-vec4
"Returns a vec4 from the object border radius."
[object]
(let [rx (:rx object)
ry (:ry object)
r1 (:r1 object)
r2 (:r2 object)
r3 (:r3 object)
r4 (:r4 object)]
(cond
(or rx ry)
#js [(:rx object) (:ry object) (:rx object) (:ry object)]
(or r1 r2 r3 r4)
#js [(:r1 object) (:r2 object) (:r3 object) (:r4 object)]
:else
#js [0.0 0.0 0.0 0.0])))
(defn resize-canvas-to
"Resize canvas to specific coordinates."
[canvas width height]
@ -75,28 +96,34 @@
(defn prepare-gl
"Prepares the WebGL context for rendering."
[gl]
(let [default-program (gl/create-program-from-sources gl default-vertex-shader default-fragment-shader)]
(.set programs "default" default-program)))
(let [default-program (gl/create-program-from-sources gl default-vertex-shader default-fragment-shader)
default-program-actives (gl/get-program-actives gl default-program)]
(js/console.log default-program-actives)
(.set programs "default" default-program)
(.set program-actives "default" default-program-actives)))
(defn render-gl
"Renders the whole document to the canvas."
[gl objects vbox]
(let [projection (.create glm/mat3)
projection (.projection glm/mat3 projection (:width vbox) (:height vbox))]
projection (.projection glm/mat3 projection (:width vbox) (:height vbox))
(.clearColor gl 1.0 0.0 1.0 0.5)
program (.get programs "default")
actives (.get program-actives "default")]
(.clearColor gl 1.0 0.0 1.0 0.5)
(.clear gl (.-COLOR_BUFFER_BIT gl))
(.viewport gl 0 0 (.-width (.-canvas gl)) (.-height (.-canvas gl)))
;; Enable alpha blending
;; Enable alpha blending
(.enable gl (.-BLEND gl))
(.blendFunc gl (.-SRC_ALPHA gl) (.-ONE_MINUS_SRC_ALPHA gl))
(.useProgram gl (.get programs "default"))
(.useProgram gl program)
(println "---------------> vbox" (:x vbox) (:width vbox) (:y vbox) (:height vbox))
(.uniformMatrix3fv gl (.getUniformLocation gl (.get programs "default") "u_projection") false projection)
(.uniform4f gl (.getUniformLocation gl (.get programs "default") "u_vbox") (:x vbox) (:y vbox) (:width vbox) (:height vbox))
(.uniformMatrix3fv gl (gl/get-program-uniform-location actives "u_projection") false projection)
(.uniform4f gl (gl/get-program-uniform-location actives "u_vbox") (:x vbox) (:y vbox) (:width vbox) (:height vbox))
(doseq [[_ object] objects]
(let [selrect (:selrect object)
@ -105,25 +132,25 @@
width (:width selrect)
height (:height selrect)
rotation (:rotation object)
;; Tengo que encontrar la forma de "reordenar la matriz" para que funcione la
;; rotación.
;; transform (:transform object)
;; {a :a b :b c :c d :d e :e f :f} transform
;; matrix #_(js/Float32Array. #js [a c 0 b d 0 0 0 1])
matrix (js/Float32Array. #js [1 0 0 0 1 0 0 0 1])
fill (first (:fills object))]
(js/console.log "fill" fill)
(js/console.log "matrix" matrix)
(.uniform1i gl (.getUniformLocation gl (.get programs "default") "u_type") (get-object-type-as-int object))
(.uniform2f gl (.getUniformLocation gl (.get programs "default") "u_size") width height)
(.uniform2f gl (.getUniformLocation gl (.get programs "default") "u_position") x y)
(.uniform1f gl (.getUniformLocation gl (.get programs "default") "u_rotation") (/ (* rotation js/Math.PI) 180.0))
#_(.uniformMatrix3fv gl (.getUniformLocation gl (.get programs "default") "u_transform") false matrix)
border (get-object-border-radius-as-vec4 object)
type (get-object-type-as-int object)]
(js/console.log border)
(.uniform4fv gl (gl/get-program-uniform-location actives "u_border") border)
(.uniform1i gl (gl/get-program-uniform-location actives "u_type") type)
(.uniform2f gl (gl/get-program-uniform-location actives "u_size") width height)
(.uniform2f gl (gl/get-program-uniform-location actives "u_position") x y)
(.uniform1f gl (gl/get-program-uniform-location actives "u_rotation") (/ (* rotation js/Math.PI) 180.0))
#_(.uniformMatrix3fv gl (gl/get-program-uniform-location actives "u_transform") false matrix)
;; NOTA: Esto es sólo aplicable en objetos que poseen fills (los textos no
;; poseen fills).
(doseq [fill (reverse (:fills object))]
(do
(.uniform4fv gl (.getUniformLocation gl (.get programs "default") "u_color") (parse-color (:fill-color fill) (:fill-opacity fill)))
(.uniform4fv gl (gl/get-program-uniform-location actives "u_color") (parse-color (:fill-color fill) (:fill-opacity fill)))
(.drawArrays gl (.-TRIANGLE_STRIP gl) 0 4)))
(doseq [stroke (reverse (:strokes object))]
(do
(.uniform4fv gl (gl/get-program-uniform-location actives "u_color") (parse-color (:stroke-color stroke) (:stroke-opacity stroke)))
(.drawArrays gl (.-TRIANGLE_STRIP gl) 0 4)))))))
(mf/defc canvas

View file

@ -57,13 +57,15 @@
[parameter get-active-name get-location-name]
(fn [gl program]
(let [count (.getProgramParameter gl program parameter)
get-active (dm/get-prop gl get-active-name)
get-location (dm/get-prop gl get-location-name)]
(into {} (for [index (range count)]
(let [info (get-active gl program index)
name (.-name info)
location (get-location gl program name)]
[name #js {:name name :info info :location location}]))))))
get-active (unchecked-get gl get-active-name)
get-location (unchecked-get gl get-location-name)
actives #js {}]
(doseq [index (range 0 count)]
(let [info (.apply get-active gl #js [program index])
name (.-name info)
location (.apply get-location gl #js [program name])]
(.defineProperty js/Object actives name #js {:value #js {:name name :info info :location location} :enumerable true :writable false :configurable false})))
actives)))
(def get-program-uniforms (get-program-active-factory (.-ACTIVE_UNIFORMS js/WebGLRenderingContext) "getActiveUniform" "getUniformLocation"))
(def get-program-attributes (get-program-active-factory (.-ACTIVE_ATTRIBUTES js/WebGLRenderingContext) "getActiveAttrib" "getAttribLocation"))
@ -75,6 +77,13 @@
attributes (get-program-attributes gl program)]
#js { :uniforms uniforms :attributes attributes }))
(defn get-program-uniform-location
"Returns the location of the given uniform in the given program"
[actives name]
(let [uniforms (unchecked-get actives "uniforms")
uniform (unchecked-get uniforms name)]
(unchecked-get uniform "location")))
;;
;; Buffers
;;
@ -90,9 +99,19 @@
;; Framebuffers
;;
(defn create-framebuffer
[gl]
[gl attachments]
(let [framebuffer (.createFramebuffer gl)]
(.bindFramebuffer gl framebuffer)
(doseq [[attachment attachment-info] attachments]
(let [attachment-type (unchecked-get attachment-info "type")
attachment-data (unchecked-get attachment-info "data")]
(cond
(= attachment-type "texture")
(.framebufferTexture2D gl (.-FRAMEBUFFER gl) attachment (.-TEXTURE_2D gl) attachment-data 0)
(= attachment-type "renderbuffer")
(.framebufferRenderbuffer gl (.-FRAMEBUFFER gl) attachment (.-RENDERBUFFER gl) attachment-data)
:else
(throw (js/Error. (dm/str "Unknown attachment type: " attachment-type))))))
(.bindFramebuffer gl nil)
framebuffer))

View file

@ -17,26 +17,45 @@ out vec4 fragColor;
in vec2 v_texCoord;
uniform int u_type;
uniform vec2 u_size;
uniform vec4 u_color;
uniform vec4 u_border;
bool isRoundedRect(in vec4 border) {
return border.x > 0.0 || border.y > 0.0 || border.z > 0.0 || border.w > 0.0;
}
// Thanks to Iñigo Quilez for this awesome functions.
// @see https://iquilezles.org/articles/distfunctions2d/
float sdRoundBox(in vec2 p, in vec2 b, in vec4 r) {
r.xy = (p.x > 0.0f) ? r.xy : r.zw;
r.x = (p.y > 0.0f) ? r.x : r.y;
vec2 q = abs(p) - b + r.x;
return min(max(q.x, q.y), 0.0f) + length(max(q, 0.0f)) - r.x;
}
float sdCircle(in vec2 p, in float r) {
return length(p) - r;
}
void main() {
// Si es un rect o un frame, simplemente asignamos el color al fragColor.
if (u_type == type_rect || u_type == type_frame) {
fragColor = u_color;
// Si es un circulo, comprobamos que el pixel este dentro del circulo, en caso
// contrario descartamos el pixel.
} else if (u_type == type_circle) {
if (length(v_texCoord - 0.5) > 0.5) {
discard;
}
if(length(v_texCoord - 0.5f) > 0.45f) {
fragColor = vec4(1.0, 0.0, 0.0, 1.0);
} else if(length(v_texCoord - 0.5f) > 0.4f) {
fragColor = vec4(1.0f, 0.0f, 1.0f, 1.0f);
if (isRoundedRect(u_border)) {
if (sdRoundBox(v_texCoord - 0.5, vec2(0.5), u_border / u_size.x) > 0.0) {
discard;
}
fragColor = u_color;
} else {
fragColor = u_color;
}
// Si es un circulo, comprobamos que el pixel este dentro del circulo, en caso
// contrario descartamos el pixel.
} else if (u_type == type_circle) {
if (sdCircle(v_texCoord - 0.5, 0.5) > 0.0) {
discard;
}
fragColor = u_color;
// Para cualquier otro elemento no soportado pintamos una especie de rejilla
// raruna.
} else {