'GRAPHICOBJECTS.INC  

  'def dyn %1*%2 : @%2=getmemory sizeof(%1)*(%3)

  macro ShaderProgram(ph)
  =======================
  glUseProgram ph
  end macro

  macro ShaderTexture(u,c,n)
  ==========================
  glUniform1i(u, c);
  glActiveTexture(GL_TEXTURE0+c);
  texture n 'openglsceneframe.inc
  end macro

  macro ShaderVector1(a,n,v)
  ==========================
  glUniform1fv a, n, v 
  end macro

  macro ShaderVector2(a,n,v)
  ==========================
  glUniform2fv a, n, v 
  end macro

  macro ShaderVector3(a,n,v)
  ==========================
  glUniform3fv a, n, v 
  end macro

  macro ShaderVector4(a,n,v)
  ==========================
  glUniform4fv a, n, v 
  end macro

  macro ShaderMatrix3(a,n,nf,v)
  =============================
  glUniformMatrix3fv a, n, nf, v 
  end macro

  macro ShaderMatrix4(a,n,nf,v)
  =============================
  glUniformMatrix4fv a, n, nf, v 
  end macro




  =================
  class ShapeObject
  =================
  '
  'e... elements for indexing vertices
  'm... matrices for instances
  'v... vertices including normal coords and texture coords / tan and bitan
  '
  bstring es,ms,vs  'source buffers
  sys    ei,mi,vi   'source buffer length used
  sys    eb,mb,vb   'opengl buffer names
  sys    ec,mc,vc   'count of elements / matrixes / vertexes
  sys    em         'mode (default GL_TRIANGLES)
  '

  'n count in floats or ints

  method append(bstring *s, sys p, int n,*ee) as sys
  ==================================================
  sys e,i,q
  e=len(s)
  q=n*4 'int or float BYTECOUNT
  if q+ee>e then s+=nuls(0x4000+q) 'STRETCH BUFFER
  int f at strptr(s)+ee
  int g at p
  for i=1 to n : f=g : @f+=4 : @g+=4 : next
  ee+=q
  end method

  method zSortMatrix(int mf=1)
  ============================
  indexbase 0
  float m at strptr ms
  'dim float*zc : @zc=getmemory 4*mc
  'dim int*idx : @idx=getmemory 4*2*mc
  dyn float zc(mc)
  dyn int idx(2*mc)
  int i
  for i=9 to mc-1
    zc[i]=m[10]+m[14] 'z
    @m+=64 'stride
  next
  sortindex zc, idx, mc
  @m=strptr ms
  string ns=left(ms,mc*64)
  sys p=strptr ns
  if mf>0
    for i=0 to mc-1
      copy @m,p+idx(i)*64,64 'ascending indexed matrix
      @m+=64 'stride
    next
  elseif mf<0
    for i=mc-1 to 0 step -1
      copy @m,p+idx(i)*64,64 'descending indexed matrix
      @m+=64 'stride
    next
  endif
  del zc
  del idx
  ns=""  
  end method

  method BillboardMatrix()
  ========================
  ' 1000
  ' 0100
  ' 001c
  ' 0001
  '
  indexbase 0
  int i
  float m at strptr ms
  for i=1 to mc
    m[ 0]=1.0 : m[ 4]=0.0 : m[ 8]=0.0 : m[12]=0.0
    m[ 1]=0.0 : m[ 5]=1.0 : m[ 9]=0.0 : m[13]=0.0
    m[ 2]=0.0 : m[ 6]=0.0 : m[10]=1.0 :          
    m[ 3]=0.0 : m[ 7]=0.0 : m[11]=0.0 : m[15]=1.0
    @m+=64
  next
  end method

  method ExpandInstance()
  =======================
  indexbase 0
  int c 'batch counter
  int i 'element batch offset
  int j 'iterator
  int k 'matrix iterator
  float m at strptr(ms)    'matrix array
  int e at strptr(es)
  float v at strptr(vs)    'vertex/norm/tex array
  string rs=nuls(32*vc*mc) 'create new vert buffer
  string fs=nuls(4*ec*mc)  'create new element buffer
  float r at strptr(rs)    'new verts
  int f at strptr(fs)      'new elements
  '
  for k=1 to mc
    for j=1 to vc 
      'VERT COORD  
      r[0] = m[0] * v[0]  + m[4] * v[1]  + m[8]  * v[2]  + m[12]
      r[1] = m[1] * v[0]  + m[5] * v[1]  + m[9]  * v[2]  + m[13]
      r[2] = m[2] * v[0]  + m[6] * v[1]  + m[10] * v[2]  + m[14]
      'NORMAL 'omits translation vector
      r[3] = m[0] * v[3]  + m[4] * v[4]  + m[8]  * v[5]
      r[4] = m[1] * v[3]  + m[5] * v[4]  + m[9]  * v[5]
      r[5] = m[2] * v[3]  + m[6] * v[4]  + m[10] * v[5]
      'TEX COORD
      r[6] = v[6]
      r[7] = v[7]
      @v+=32 'STRIDE BYTES
      @r+=32
    next
    for j=1 to ec
      f=e+c
      @e+=4
      @f+=4
    next 
    c+=vc 'stride instance batch
    @v=strptr vs 'reset
    @e=strptr es 'reset
    @m+=64 'next instance matrix
  next
  vs=rs  'new replace verts
  es=fs  'new replace elements
  vc*=mc 'update vert count
  ec*=mc 'update element count
  ms=nuls(64) 'new single identity matrix
  float m at strptr ms
  setidentity m,4
  mc=1
  end method

  method putvertex(float*d, int n) as sys
  =======================================
  append vs,@d,n,vi '(stepping 32 bytes)
  vc=vc+vi>>5 'vert norm tex 
  end method

  method putindex(int*d, int n, m=GL_TRIANGLES) as sys
  ====================================================
  em=m
  append es,@d,n,ei '(stepping 4 bytes)
  ec=ec+ei>>2
  end method

  method putmatrix(float*d, int n) as sys
  =======================================
  append ms,@d,n,mi '(stepping 64 bytes)
  mc=mc+mi>>6 '4x4 matrix
  end method

  method clearVertex()
  ====================
  vi=0 : vc=0
  end method

  method clearIndex()
  ===================
  ei=0 : ec=0 : em=0
  end method

  method clearMatrix()
  ====================
  mi=0 : mc=0
  end method

  method init
  ===========
  vs=""
  ms=""
  es=""
  glGenBuffers  1, vb
  glGenBuffers  1, mb
  glGenBuffers  1, eb
  end method

  method SetAttributes(int mo=0)
  ==============================
  '
  'ATTRIBUTE LOCATION NAMES
  % v_vertex = 0
  % v_normal = 1
  % v_texcor = 2
  % v_tan    = 3
  % v_bitan  = 4
  % v_matrix = 5 '5 6 7 8 (each column of the matrix)

  int i
  int stride = 32 '(3+3+2)*sizeof float
  if mo=1 then stride+=24 '(3+3)*sizeof float 'TAN AND BITAN FOR NORMAL MAPPING
  '
  % vap   =  glVertexAttribPointer
  % f     =  GL_FLOAT
  '
  glBindBuffer GL_ARRAY_BUFFER, vb
  '
  '----------------------------------------------
  'call attribute    size type nrm stride  offset
  '----------------------------------------------
  vap   v_vertex   , 3,   f,   0,  stride, 00 '0
  vap   v_normal   , 3,   f,   0,  stride, 12 '3
  vap   v_texcor   , 2,   f,   0,  stride, 24 '6
  if mo then
  vap   v_tan      , 3,   f,   0,  stride, 32 '8
  vap   v_bitan    , 3,   f,   0,  stride, 44 '11
  endif
  

  glBindBuffer GL_ARRAY_BUFFER, mb
  '
  for i=0 to 3
  'call attribute    size  type nrm stride offset
  '------------------------------------------------------
  vap   v_matrix+i , 4,    f,   0,  64,    i*16 '0 4 8 12
  '------------------------------------------------------
  glVertexAttribDivisor(v_matrix+i, 1)
  next
  glBindBuffer GL_ARRAY_BUFFER, 0
  '
  end method

  method transferVertex()
  =======================
  glBindBuffer GL_ARRAY_BUFFER, vb
  glBufferData GL_ARRAY_BUFFER, vc*32, strptr(vs), GL_STATIC_DRAW
  end method

  method transferElement()
  ========================
  glBindBuffer GL_ELEMENT_ARRAY_BUFFER, eb
  glBufferData GL_ELEMENT_ARRAY_BUFFER, ec*4, strptr(es), GL_STATIC_DRAW
  end method

  method transferMatrix()
  =======================
  glBindBuffer GL_ARRAY_BUFFER, mb
  glBufferData GL_ARRAY_BUFFER, mc*64, strptr(ms), GL_STATIC_DRAW
  end method

  method show()
  =============
  string tab=chr(9), cm=chr(44), cr=chr(13,10)
  print "BUFFER OBJECT DATA" cr cr+
  tab "vertex" tab "matrix" tab "index" cr+
  -----------------------------------------
  "names:" tab vb tab mb tab eb cr+
  "count:" tab vc tab mc tab ec cr+
  "size:" vi tab mi tab ei cr+
   ""
  end method

  method transfer()
  =================
  'show 
  transferVertex
  transferMatrix
  transferElement
  end method

  method release()
  ================
  'sys i : for i= 0 to 8 : glDisableVertexAttribArray i : next
  def delete glDeleteBuffers
  delete  1, vb 
  delete  1, eb
  delete  1, mb
  del vs
  del es
  del ms
  end method

  method render(sys p=0, c=0)
  ===========================
  'INDEXED
  SetAttributes()
  if not p
    glBindBuffer GL_ELEMENT_ARRAY_BUFFER, eb
    if not c
      c=ec
    endif
  endif
  int i : for i= 0 to 8 : glEnableVertexAttribArray i : next
  glDrawElementsInstanced( em, c, GL_UNSIGNED_INT, byval p, mc )
  'glDrawElementsInstancedBaseVertex( em, ec, GL_UNSIGNED_INT, byval p, mc, 0 )
  'glDrawElementsInstancedBaseVertexBaseInstance( em, ec, GL_UNSIGNED_INT, byval p, mc, 0, 0 )
  int i : for i= 0 to 8 : glDisableVertexAttribArray i : next
  end method

  method renderClient(sys p=0, c=0)
  =================================
  'INDEXED
  if not p
    p=strptr(es)
    if not c
      c=ec
    endif
  endif
  glEnableClientState( GL_VERTEX_ARRAY )
  glVertexPointer( 3, GL_FLOAT, 32, strptr(vs)+0 )
  glNormalPointer( GL_FLOAT, 32, strptr(vs)+12 )
  glTexCoordPointer( 2, GL_FLOAT, 32, strptr(vs)+24 )
  glDrawElements( em, c, GL_UNSIGNED_INT, byval p )
  glDisableClientState( GL_VERTEX_ARRAY )
  end method

  end class 'ShapeObject
  '#recordof ShapeObject

  ==================
  class RenderObject
  ==================

  'Render To Texture
  'https://learnopengl.com/Advanced-OpenGL/Framebuffers
  'https:/+++/www.khronos.org/registry/OpenGL-Refpages/gl4/

  int  Framebuf
  'int  Depthbuf
  int  DepthStencilbuf
  int  Texturebuf
  int  txWidth
  int  txHeight
  int  texture
  int  ntype
  int  selBuf
  '
  method Setup(int txw=512, txh=512, typ=GL_UNSIGNED_BYTE)
  ========================================================
  txwidth=txw
  txheight=txh
  typ=GL_FLOAT
  ntype=typ 'GL_UNSIGNED_BYTE 'GL_FLOAT
  '
  'Create New FrameBuffer
  glGenFramebuffers(1, Framebuf)
  glBindFramebuffer(GL_FRAMEBUFFER, Framebuf)
  '
  'Create Texture Buffer
  'glGenTextures(1, Texturebuf)
  Texture = ++texe
  Texturebuf=texn[texture]
  glBindTexture(GL_TEXTURE_2D, Texturebuf)
  ' Give an empty image to OpenGL ( the end null )
  glTexImage2D(GL_TEXTURE_2D, 0,GL_RGBA, txWidth, txHeight, 0,GL_RGBA, ntype, null)
  ' Poor filtering. Needed !
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST)
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST)
  glBindTexture(GL_TEXTURE_2D, 0);
  '
  'Attach Texture Buffer
  glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, Texturebuf, 0)
  'glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
  'GL_TEXTURE_2D, Texturebuf, 0); 
  '
  'using texture buffers
  'combined depth and stencil buffer attachments
  'glTexImage2D(
  '  GL_TEXTURE_2D, 0, GL_DEPTH24_STENCIL8, txWidth, txHeight, 0, 
  '  GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, NULL
  ')
  'glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT,
  'GL_TEXTURE_2D, Texturebuf, 0)
  '
  'using Render buffers
  'Depth Buffer attachment
  'glGenRenderbuffers(1, Depthbuf)
  'glBindRenderbuffer(GL_RENDERBUFFER, depthbuf)
  'glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, txWidth, txHeight)
  'glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthbuf)
  '
  'combined depth and stencil buffer attachments
  glGenRenderbuffers(1, DepthStencilbuf);
  glBindRenderbuffer(GL_RENDERBUFFER, DepthStencilbuf); 
  glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, txWidth, txHeight);  
  glBindRenderbuffer(GL_RENDERBUFFER, 0);
  glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, DepthStencilbuf) 


  ' Set the list of draw buffers
  'GLenum DrawBuffers[1] = {GL_COLOR_ATTACHMENT0}
  'glDrawBuffers(1, GL_COLOR_ATTACHMENT0); // "1" is the size of DrawBuffers

  end method 'setup

  method Check() as int
  =====================
  ' Always check that our framebuffer is ok
  if glCheckFramebufferStatus(GL_FRAMEBUFFER) <> GL_FRAMEBUFFER_COMPLETE
    return false
  endif
  return 1
  end method

  method RenderToTexture()
  ========================
  glBindFramebuffer(GL_FRAMEBUFFER, Framebuf)
  glViewport(0,0,txwidth,txheight)
  Selbuf=Framebuf
  end method

  method RenderToScreen()
  =======================
  glBindFramebuffer(GL_FRAMEBUFFER, 0)
  RECT cRect
  GetClientRect  gWnd,cRect
  glViewport 0, 0, crect.right, crect.bottom
  Selbuf=0
  end method

  method ByteCount(int nx=0, ny=0) as int
  =======================================
  int w
  if ntype=GL_FLOAT
    w=16
  else
    w=4 'assume bytes
  endif
  if nx<=0
    nx=txWidth : ny=txHeight
  endif 
  return w*nx*ny 
  end method

  method Read(sys pp=0, int px=0, py=0, nx=0, ny=0)
  =================================================
  if nx<=0
    nx=txWidth : ny=txHeight
  endif
  if pp
    if Selbuf=0
      RenderToTexture
      SelBuf=0
    endif
    glReadPixels(px,py,txWidth, txHeight, GL_RGBA, ntype, pp)
    if Selbuf=0
      RenderToScreen 'Selbuf=0
    endif
  endif
  end method

  method Release()
  ================
  RenderToScreen
  glDeleteRenderbuffers( 1, DepthStencilbuf )
  glDeleteFramebuffers( 1, Framebuf )
  'glDeleteTextures 1,Texturebuf
  end method

  end class 'RenderObject
  '#recordof renderobject

