<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      從0開發3D引擎(十二):使用領域驅動設計,從最小3D程序中提煉引擎(第三部分)

      大家好,本文根據領域驅動設計的成果,實現了init API。

      上一篇博文

      從0開發3D引擎(十一):使用領域驅動設計,從最小3D程序中提煉引擎(第二部分)

      下一篇博文

      從0開發3D引擎(十三):使用領域驅動設計,從最小3D程序中提煉引擎(第四部分)

      繼續實現

      實現“DirectorJsAPI.init”

      實現“保存WebGL上下文”限界上下文

      1、在src/api_layer/api/中加入DirectorJsAPI.re,實現API
      DirectorJsAPI.re代碼為:

      let init = DirectorApService.init;
      

      2、在src/infrastructure_layer/external/external_object/中加入Error.re,負責處理“js異常”這個外部對象
      Error.re代碼為:

      //根據錯誤信息(string類型),創建并拋出“js異常”對象
      let error = msg => Js.Exn.raiseError(msg);
      
      //根據“js異常”對象,拋出它
      let throwError: Js.Exn.t => unit = [%raw err => {|
      throw err;
      |}];
      

      3、在src/application_layer/service/中加入DirectorApService.re,實現應用服務
      DirectorApService.re代碼為:

      let init = contextConfigJsObj => {
        CanvasCanvasEntity.getCanvas()
        |> OptionContainerDoService.get
        //OptionContainerDoService.get函數返回的是Result容器的包裝值,需要調用ResultContainerVO.bind函數來處理容器內部的值
        |> ResultContainerVO.bind(canvas => {
             SetWebGLContextSetWebGLContextDoService.setGl(
               contextConfigJsObj,
               canvas,
             )
           })
           //應用服務DirectorApService負責用拋出異常的方式處理Result錯誤
           |> ResultContainerVO.handleFail(Error.throwError);
      };
      

      關于bind函數的使用,可以參考從0開發3D引擎(五):函數式編程及其在引擎中的應用->bind

      4、修改CanvasCanvasEntity.re,實現getCanvas函數
      CanvasCanvasEntity.re相關代碼為:

      let getCanvas = () => {
        Repo.getCanvas();
      };
      

      5、把最小3D程序的WebGL1.re放到src/infrastructure_layer/external/library/中,保留所有的代碼
      WebGL1.re代碼為:

      open Js.Typed_array;
      
      type webgl1Context;
      
      type program;
      
      type shader;
      
      type buffer;
      
      type attributeLocation = int;
      
      type uniformLocation;
      
      type bufferTarget =
        | ArrayBuffer
        | ElementArrayBuffer;
      
      type usage =
        | Static;
      
      type contextConfigJsObj = {
        .
        "alpha": bool,
        "depth": bool,
        "stencil": bool,
        "antialias": bool,
        "premultipliedAlpha": bool,
        "preserveDrawingBuffer": bool,
      };
      
      [@bs.send]
      external getWebGL1Context:
        ('canvas, [@bs.as "webgl"] _, contextConfigJsObj) => webgl1Context =
        "getContext";
      
      [@bs.send.pipe: webgl1Context] external createProgram: program = "";
      
      [@bs.send.pipe: webgl1Context] external useProgram: program => unit = "";
      
      [@bs.send.pipe: webgl1Context] external linkProgram: program => unit = "";
      
      [@bs.send.pipe: webgl1Context]
      external shaderSource: (shader, string) => unit = "";
      
      [@bs.send.pipe: webgl1Context] external compileShader: shader => unit = "";
      
      [@bs.send.pipe: webgl1Context] external createShader: int => shader = "";
      
      [@bs.get] external getVertexShader: webgl1Context => int = "VERTEX_SHADER";
      
      [@bs.get] external getFragmentShader: webgl1Context => int = "FRAGMENT_SHADER";
      
      [@bs.get] external getHighFloat: webgl1Context => int = "HIGH_FLOAT";
      
      [@bs.get] external getMediumFloat: webgl1Context => int = "MEDIUM_FLOAT";
      
      [@bs.send.pipe: webgl1Context]
      external getShaderParameter: (shader, int) => bool = "";
      
      [@bs.get] external getCompileStatus: webgl1Context => int = "COMPILE_STATUS";
      
      [@bs.get] external getLinkStatus: webgl1Context => int = "LINK_STATUS";
      
      [@bs.send.pipe: webgl1Context]
      external getProgramParameter: (program, int) => bool = "";
      
      [@bs.send.pipe: webgl1Context]
      external getShaderInfoLog: shader => string = "";
      
      [@bs.send.pipe: webgl1Context]
      external getProgramInfoLog: program => string = "";
      
      [@bs.send.pipe: webgl1Context]
      external attachShader: (program, shader) => unit = "";
      
      [@bs.send.pipe: webgl1Context]
      external bindAttribLocation: (program, int, string) => unit = "";
      
      [@bs.send.pipe: webgl1Context] external deleteShader: shader => unit = "";
      
      [@bs.send.pipe: webgl1Context] external createBuffer: buffer = "";
      
      [@bs.get]
      external getArrayBuffer: webgl1Context => bufferTarget = "ARRAY_BUFFER";
      
      [@bs.get]
      external getElementArrayBuffer: webgl1Context => bufferTarget =
        "ELEMENT_ARRAY_BUFFER";
      
      [@bs.send.pipe: webgl1Context]
      external bindBuffer: (bufferTarget, buffer) => unit = "";
      
      [@bs.send.pipe: webgl1Context]
      external bufferFloat32Data: (bufferTarget, Float32Array.t, usage) => unit =
        "bufferData";
      
      [@bs.send.pipe: webgl1Context]
      external bufferUint16Data: (bufferTarget, Uint16Array.t, usage) => unit =
        "bufferData";
      
      [@bs.get] external getStaticDraw: webgl1Context => usage = "STATIC_DRAW";
      
      [@bs.send.pipe: webgl1Context]
      external getAttribLocation: (program, string) => attributeLocation = "";
      
      [@bs.send.pipe: webgl1Context]
      external getUniformLocation: (program, string) => Js.Null.t(uniformLocation) =
        "";
      
      [@bs.send.pipe: webgl1Context]
      external vertexAttribPointer:
        (attributeLocation, int, int, bool, int, int) => unit =
        "";
      
      [@bs.send.pipe: webgl1Context]
      external enableVertexAttribArray: attributeLocation => unit = "";
      
      "";
      
      [@bs.send.pipe: webgl1Context]
      external uniformMatrix4fv: (uniformLocation, bool, Float32Array.t) => unit =
        "";
      
      [@bs.send.pipe: webgl1Context]
      external uniform1i: (uniformLocation, int) => unit = "";
      
      [@bs.send.pipe: webgl1Context]
      external uniform3f: (uniformLocation, float, float, float) => unit = "";
      
      [@bs.send.pipe: webgl1Context]
      external drawElements: (int, int, int, int) => unit = "";
      
      [@bs.get] external getFloat: webgl1Context => int = "FLOAT";
      
      [@bs.send.pipe: webgl1Context]
      external clearColor: (float, float, float, float) => unit = "";
      
      [@bs.send.pipe: webgl1Context] external clear: int => unit = "";
      
      [@bs.get]
      external getColorBufferBit: webgl1Context => int = "COLOR_BUFFER_BIT";
      
      [@bs.get]
      external getDepthBufferBit: webgl1Context => int = "DEPTH_BUFFER_BIT";
      
      [@bs.get] external getDepthTest: webgl1Context => int = "DEPTH_TEST";
      
      [@bs.send.pipe: webgl1Context] external enable: int => unit = "";
      
      [@bs.get] external getTriangles: webgl1Context => int = "TRIANGLES";
      
      [@bs.get] external getUnsignedShort: webgl1Context => int = "UNSIGNED_SHORT";
      
      [@bs.get] external getCullFace: webgl1Context => int = "CULL_FACE";
      
      [@bs.send.pipe: webgl1Context] external cullFace: int => unit = "";
      
      [@bs.get] external getBack: webgl1Context => int = "BACK";
      

      6、在src/domain_layer/domain/init/set_webgl_context/service/中加入SetWebGLContextSetWebGLContextDoService.re,創建領域服務SetWebGLContext
      SetWebGLContextSetWebGLContextDoService.re代碼為:

      let setGl = (contextConfigJsObj, canvas): ResultContainerVO.t(unit, Js.Exn.t) => {
        ContextContextEntity.setGl(contextConfigJsObj, canvas)
        |> ResultContainerVO.succeed;
      };
      

      7、修改ContextContextEntity.re,實現setGl函數
      ContextContextEntity.re相關代碼為:

      let setGl = (contextConfigJsObj, canvas) => {
        ContextRepo.setGl(WebGL1.getWebGL1Context(canvas, contextConfigJsObj));
      };
      

      8、修改ContextPOType.re,定義Context PO的gl字段的數據類型
      ContextPOType.re相關代碼為:

      type context = {
        gl: option(WebGL1.webgl1Context),
        ...
      };
      

      9、修改ContextRepo.re,實現倉庫對Context PO的gl字段的操作
      ContextRepo.re代碼為:

      let getGl = gl => {
        //將Option轉換為Result
        Repo.getContext().gl |> OptionContainerDoService.get;
      };
      
      let setGl = gl => {
        Repo.setContext({...Repo.getContext(), gl: Some(gl)});
      };
      

      10、修改CreateRepo.re,實現創建Context PO的gl字段
      CreateRepo.re相關代碼為:

      let create = () => {
        ...
        context: {
          gl: None,
          ...
        },
      };
      

      實現“初始化所有Shader”限界上下文

      1、重寫DirectorApService.re
      DirectorApService.re代碼為:

      let init = contextConfigJsObj => {
        CanvasCanvasEntity.getCanvas()
        |> ResultContainerVO.bind(canvas => {
             SetWebGLContextSetWebGLContextDoService.setGl(
               contextConfigJsObj,
               canvas,
             )
             |> ResultContainerVO.bind(() => {InitShaderInitShaderDoService.init()})
           })
        |> ResultContainerVO.handleFail(Error.throwError);
      };
      

      2、加入值對象InitShader

      從0開發3D引擎(十):使用領域驅動設計,從最小3D程序中提煉引擎(第一部分)的“設計值對象InitShader”中,我們已經定義了值對象InitShader的類型,所以我們直接將設計轉換為實現:
      在src/domain_layer/domain/init/init_shader/value_object/中加入InitShaderInitShaderVO.re,創建值對象InitShader
      InitShaderInitShaderVO.re代碼為:

      type singleInitShader = {
        shaderId: string,
        vs: string,
        fs: string,
      };
      
      type t = list(singleInitShader);
      

      3、在src/domain_layer/domain/shader/shader/value_object/中加入ProgramShaderVO.re,創建值對象Program,它的DO對應一個WebGL的program對象
      ProgramShaderVO.re代碼為:

      type t =
        | Program(WebGL1.program);
      
      let create = program => Program(program);
      
      let value = program =>
        switch (program) {
        | Program(value) => value
        };
      

      4、修改聚合根ShaderManager的DO

      根據識別的引擎邏輯:

      • 在初始化所有Shader時,創建每個Program
      • 在渲染每個三角形時,根據Shader名稱獲得關聯的Program

      我們需要根據Shader id獲得關聯的Program,所以在ShaderManager DO中應該加入一個immutable hash map,它的key為Shader id,value為值對象Program的DO。

      應該在領域視圖的“容器”限界上下文中,加入值對象ImmutableHashMap、值對象MutableHashMap,其中ImmutableHashMap用于實現不可變的hash map,MutableHashMap用于實現可變的hash map。

      現在來具體實現它們:
      1)在src/domain_layer/domain/structure/container/value_object/中創建文件夾hash_map/
      2)在hash_map/文件夾中加入ImmutableHashMapContainerVO.re、MutableHashMapContainerVO.re、HashMapContainer.re、HashMapContainerType.re
      ImmutableHashMapContainerVO.re負責實現Immutable Hash Map;
      MutableHashMapContainerVO.re負責實現Mutable Hash Map;
      HashMapContainer.re從兩者中提出的公共代碼;
      HashMapContainerType.re定義HashMap的類型。

      因為HashMapContainer需要使用reduce來遍歷數組,這個操作屬于通用操作,應該作為領域服務,所以在領域視圖的“容器”限界上下文中,加入領域服務Array。在src/domain_layer/domain/structure/container/service/中加入ArrayContainerDoService.re,創建領域服務Array。

      相關代碼如下:
      ArrayContainterDoService.re

      let reduceOneParam = (func, param, arr) => {
        //此處為了優化,使用for循環和mutable變量來代替Array.reduce
        let mutableParam = ref(param);
        for (i in 0 to Js.Array.length(arr) - 1) {
          mutableParam := func(. mutableParam^, Array.unsafe_get(arr, i));
        };
        mutableParam^;
      };
      

      HashMapContainerType.re

      type t('key, 'value) = Js.Dict.t('value);
      type t2('value) = t(string, 'value);
      

      HashMapContainer.re

      let createEmpty = (): HashMapContainerType.t2('a) => Js.Dict.empty();
      
      let get = (key: string, map: HashMapContainerType.t2('a)) =>
        Js.Dict.get(map, key);
      
      let entries = (map: HashMapContainerType.t2('a)): array((Js.Dict.key, 'a)) =>
        map |> Js.Dict.entries;
      
      let _mutableSet = (key: string, value, map) => {
        Js.Dict.set(map, key, value);
        map;
      };
      
      let _createEmpty = (): Js.Dict.t('a) => Js.Dict.empty();
      
      let copy = (map: HashMapContainerType.t2('a)): HashMapContainerType.t2('a) =>
        map
        |> entries
        |> ArrayContainerDoService.reduceOneParam(
             (. newMap, (key, value)) => newMap |> _mutableSet(key, value),
             _createEmpty(),
           );
      

      ImmutableHashMapContainerVO.re

      type t('key, 'value) = HashMapContainerType.t('key, 'value);
      
      let createEmpty = HashMapContainer.createEmpty;
      
      let set =
          (key: string, value: 'a, map: HashMapContainerType.t2('a))
          : HashMapContainerType.t2('a) => {
        let newMap = map |> HashMapContainer.copy;
      
        Js.Dict.set(newMap, key, value);
      
        newMap;
      };
      
      let get = HashMapContainer.get;
      

      MutableHashMap.re

      type t('key, 'value) = HashMapContainerType.t('key, 'value);
      
      let createEmpty = HashMapContainer.createEmpty;
      
      let set = (key: string, value: 'a, map: HashMapContainerType.t2('a)) => {
        Js.Dict.set(map, key, value);
      
        map;
      };
      
      let get = HashMapContainer.get;
      

      現在我們可以通過修改ShaderManagerShaderEntity.re來修改ShaderManager的DO,加入programMap字段
      ShaderManagerShaderEntity.re相關代碼為:

      type t = {
        ...
        programMap:
          ImmutableHashMapContainerVO.t2(ShaderShaderEntity.t, ProgramShaderVO.t),
      };
      

      5、創建領域服務BuildInitShaderData,實現構造值對象InitShader
      1)在src/domain_layer/domain/init/init_shader/service/中加入BuildInitShaderDataInitShaderDoService.re,創建領域服務BuildInitShaderData
      BuildInitShaderDataInitShaderDoService.re代碼為:

      let build = () => {
        ShaderManagerShaderEntity.getAllGLSL()
        |> List.map(((shaderName, glsl)) => {
             (
               {
                 shaderId: ShaderShaderEntity.getId(shaderName),
                 vs: GLSLShaderVO.getVS(glsl),
                 fs: GLSLShaderVO.getFS(glsl),
               }: InitShaderInitShaderVO.singleInitShader
             )
           });
      };
      

      2)修改GLSLShaderVO.re,實現getVS、getFS函數
      GLSLShaderVO.re相關代碼為:

      let getVS = glsl =>
        switch (glsl) {
        | GLSL(vs, fs) => vs
        };
      
      let getFS = glsl =>
        switch (glsl) {
        | GLSL(vs, fs) => fs
        };
      

      3)修改ShaderManagerShaderEntity.re,加入getAllGLSL函數
      ShaderManagerShaderEntity.re相關代碼為:

      let getAllGLSL = () => {
        ShaderManagerRepo.getAllGLSL();
      };
      

      4)修改ShaderManagerRepo.re,加入getAllGLSL函數
      ShaderManagerShaderEntity.re相關代碼為:

      let getAllGLSL = () => {
        Repo.getShaderManager().glsls
        |> List.map(((shaderId, (vs, fs))) => {
             (ShaderShaderEntity.create(shaderId), GLSLShaderVO.create((vs, fs)))
           });
      };
      

      6、在src/domain_layer/domain/init/init_shader/service/中加入InitShaderInitShaderDoService.re,創建領域服務InitShader
      InitShaderInitShaderDoService.re代碼為:

      let init = (): ResultContainerVO.t(unit, Js.Exn.t) => {
        ContextContextEntity.getGl()
        |> ResultContainerVO.bind(gl => {
             //從著色器DO數據中構建值對象InitShader
             BuildInitShaderDataInitShaderDoService.build()
             |> ResultContainerVO.tryCatch(initShaderData => {
                  initShaderData
                  |> List.iter(
                       (
                         {shaderId, vs, fs}: InitShaderInitShaderVO.singleInitShader,
                       ) => {
                       let program = ContextContextEntity.createProgram(gl);
      
                       /* 注意:領域服務不應該直接依賴Repo
      
                          應該通過實體ContextContextEntity而不是ShaderManagerRepo來將program設置到ShaderManager PO的programMap中!
                          */
                       ContextContextEntity.setProgram(shaderId, program);
      
                       ContextContextEntity.initShader(vs, fs, program, gl)
                       |> ignore;
      
                       //用于運行測試
                       Js.log((shaderId, vs, fs));
                     })
                })
           });
      };
      

      7、修改ContextContextEntity.re,實現相關函數
      ContextContextEntity.re相關代碼為:

      let getGl = () => {
        ContextRepo.getGl();
      };
      
      ...
      
      let createProgram = gl => gl |> WebGL1.createProgram;
      
      let setProgram = (shaderId, program) => {
        ShaderManagerRepo.setProgram(shaderId, program);
      };
      
      let _compileShader = (gl, glslSource, shader) => {
        WebGL1.shaderSource(shader, glslSource, gl);
        WebGL1.compileShader(shader, gl);
      
        WebGL1.getShaderParameter(shader, WebGL1.getCompileStatus(gl), gl)
        === false
          ? {
            let message = WebGL1.getShaderInfoLog(shader, gl);
      
            //這里為了實現“從0開發3D引擎(十):使用領域驅動設計,從最小3D程序中提煉引擎(第一部分)”提出的“處理錯誤優化”,用“拋出異常”而不是Result來處理錯誤
            Error.error(
              {j|shader info log: $message
              glsl source: $glslSource
              |j},
            );
          }
          : shader;
      };
      
      let _linkProgram = (program, gl) => {
        WebGL1.linkProgram(program, gl);
      
        WebGL1.getProgramParameter(program, WebGL1.getLinkStatus(gl), gl) === false
          ? {
            let message = WebGL1.getProgramInfoLog(program, gl);
      
            //這里為了實現“從0開發3D引擎(十):使用領域驅動設計,從最小3D程序中提煉引擎(第一部分)”提出的“處理錯誤優化”,用“拋出異常”而不是Result來處理錯誤
            Error.error({j|link program error: $message|j});
          }
          : program;
      };
      
      let initShader = (vsSource: string, fsSource: string, program, gl) => {
        let vs =
          _compileShader(
            gl,
            vsSource,
            WebGL1.createShader(WebGL1.getVertexShader(gl), gl),
          );
        let fs =
          _compileShader(
            gl,
            fsSource,
            WebGL1.createShader(WebGL1.getFragmentShader(gl), gl),
          );
      
        WebGL1.attachShader(program, vs, gl);
        WebGL1.attachShader(program, fs, gl);
      
        WebGL1.bindAttribLocation(program, 0, "a_position", gl);
      
        _linkProgram(program, gl);
      
        WebGL1.deleteShader(vs, gl);
        WebGL1.deleteShader(fs, gl);
      
        program;
      };
      

      8、修改ShaderManagerPOType.re,ShaderManager PO加入programMap字段

      雖然programMap也是hash map,但不能直接使用領域層的值對象ImmutableHashMapContainerVO來定義它的類型!因為PO屬于基礎設施層,它不能依賴領域層!
      因此,我們應該在基礎設施層的“數據”中創建一個ImmutableHashMap.re模塊,盡管它的類型和函數都與ImmutableHashMapContainerVO一樣。

      在src/infrastructure_layer/data/中創建文件夾structure/,在該文件夾中加入ImmutableHashMap.re。
      為了方便,目前暫時直接用ImmutableHashMapContainerVO來實現ImmutableHashMap。
      ImmutableHashMap.re代碼為:

      type t2('key, 'a) = ImmutableHashMapContainerVO.t2('key, 'a);
      
      let createEmpty = ImmutableHashMapContainerVO.createEmpty;
      
      let set = ImmutableHashMapContainerVO.set;
      

      修改ShaderManagerPOType.re,ShaderManager PO加入programMap字段:

      type shaderManager = {
        ...
        programMap: ImmutableHashMap.t2(shaderId, WebGL1.program),
      };
      

      9、修改ShaderManagerRepo.re,實現setProgram函數
      ShaderManagerRepo.re相關代碼為:

      let _getProgramMap = ({programMap}) => programMap;
      
      let setProgram = (shaderId, program) => {
        Repo.setShaderManager({
          ...Repo.getShaderManager(),
          programMap:
            _getProgramMap(Repo.getShaderManager())
            //這里也使用基礎設施層的“數據”的ImmutableHashMap,因為操作的是ShaderManager PO的programMap
            |> ImmutableHashMap.set(shaderId, program),
        });
      };
      

      10、修改CreateRepo.re,實現創建ShaderManager PO的programMap字段
      CreateRepo.re相關代碼為:

      let create = () => {
        ...
        shaderManager: {
          ...
          programMap: ImmutableHashMap.createEmpty(),
        },
      };
      

      實現用戶代碼并運行測試

      1、在項目根目錄上執行webpack命令,更新wd.js文件

      yarn webpack
      

      2、實現index.html相關代碼

      index.html代碼為:

        <script>
          ...
          //準備webgl上下文的配置項
          var contextConfig = {
            "alpha": true,
            "depth": true,
            "stencil": false,
            "antialias": true,
            "premultipliedAlpha": true,
            "preserveDrawingBuffer": false,
          };
      
          wd.Director.init(contextConfig);
        </script>
      

      3、運行測試

      運行index.html頁面

      打開控制臺,可以看到打印了兩次數組,每次數組內容為[Shader名稱, vs, fs],其中第一次的Shader名稱為“shader2”,第二次為“shader1”

      posted @ 2020-03-05 08:33  楊元超  閱讀(476)  評論(0)    收藏  舉報
      主站蜘蛛池模板: 亚洲第一香蕉视频啪啪爽| 阳朔县| 色综合中文综合网| 国产成人精品一区二三区在线观看| 无码一区二区三区视频| 亚洲国产精品综合久久20| 野花香视频在线观看免费高清版| 亚洲精品久久无码av片软件| 亚洲第一极品精品无码久久| 国产性色av高清在线观看| 香蕉久久夜色精品国产成人| 亚洲国产一区二区三区久| 色五月丁香六月欧美综合| 日本道不卡一二三区视频| 亚洲中文字幕在线二页| 日本丰满白嫩大屁股ass| 91亚洲精品一区二区三区| 国产乱啊有帅gv小太正| 亚洲一区二区三区蜜桃臀| 强奷漂亮少妇高潮伦理| 亚洲日韩一区精品射精| 欧美激欧美啪啪片| 国内精品久久久久影院网站| 国产精品亚洲综合久久小说| 国产无套内射又大又猛又粗又爽| 久久精品国产亚洲av天海翼| 女高中生自慰污污网站| 中文字幕亚洲综合久久蜜桃| 小伙无套内射老熟女精品| 色综合久久中文字幕综合网| 欧美啪啪网| 精品人妻日韩中文字幕| 亚洲国产午夜理论片不卡| 午夜爽爽爽男女免费观看影院| 中文字幕少妇人妻精品| 色悠悠成人综合在线视频| 成人午夜免费无码视频在线观看| 国产女人18毛片水真多1| 久久精产国品一二三产品| 真实国产精品视频400部| 中文字幕日韩有码第一页|