/* * LaGUI: A graphical application framework. * Copyright (C) 2022 Wu Yiming * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "la_5.h" #include #include "freetype/ftadvanc.h" char TNS_VERTEX_SIMPLE_MATCAP[] = "#version 330\n" "uniform mat4 mProjection;\n" "uniform mat4 mModel;\n" "uniform mat4 mView;\n" "\n" "in vec4 vVertex;\n" "in vec3 vNormal;\n" "smooth out vec3 fNormal;\n" "\n" "void main(){\n" " gl_Position = mProjection * mView * mModel * vVertex;\n" " vec3 N = ( mView * mModel * vec4(vNormal,0)).xyz;\n" " fNormal = normalize(N);\n" "}"; char TNS_FRAGMENT_SIMPLE_MATCAP[] = "#version 330\n" "\n" "smooth in vec3 fNormal;" "\n" "float Interpolate(float between1,float between2,float value1,float value2,float key){\n" " float i = (key-between1)/(between2-between1);\n" " return value1*(1-i)+value2*i;" "}\n" "void main(){\n" " float value = dot(vec3(0,0,1),fNormal);\n" " if(value<0.65) value=0.15;\n" " else if(value>=0.65 && value<0.85) value=Interpolate(0.65,0.85,0.15,0.75,value);\n" " else if(value>=0.85 && value<0.95) value=0.75;\n" " else if(value>=0.95) value=0.9;\n" " gl_FragColor = vec4(vec3(0.84, 0.41, 0.16)*value,1);\n" "}"; char TNS_VERTEX_GRID[] = "#version 330\n" "\n" "uniform mat4 mProjection;\n" "uniform mat4 mModel;\n" "uniform mat4 mView;\n" "\n" "in vec4 vVertex;\n" "in vec4 vColor;\n" "in vec2 vUV;\n" "out vec4 fColor;\n" "out vec2 uv;\n" "\n" "void main(){\n" " vec4 pos = mProjection * mView * mModel * vVertex;\n" " gl_Position = pos;\n" " fColor = vColor;\n" " uv = vUV;\n" "}"; char TNS_FRAGMENT_TRANSPARNT_GRID[] = "#version 330\n" "\n" "in vec4 fColor;\n" "in vec2 uv;\n" "\n" "void main(){\n" " vec4 c = fColor;\n" " c.a = sin(uv.x)*sin(uv.y)>0?c.a:0;\n" " gl_FragColor = c;\n" "}"; const char LA_IMM_VERTEX_SHADER[] = "#version 330\n\ uniform mat4 mProjection;\ uniform mat4 mModel;\ uniform mat4 mView;\ in vec4 vVertex;\ in vec4 vColor;\ in vec3 vNormal;\ in vec2 vUV;\ out vec4 fColor;\ out vec2 fUV;\ flat out vec3 fNormal;\ out vec3 fGPos;\ void main(){\ gl_Position = mProjection * mView * mModel * vVertex;\ fColor = vColor;\ fUV=vUV;\ fGPos=vec3((mModel * vVertex).xyz);\ fNormal= (mModel * vec4(vNormal,0.)).xyz;\ }"; const char LA_IMM_FRAGMENT_SHADER[] = "#version 330\n\ uniform sampler2D TexColor;\ uniform sampler2DMS TexColorMS;\ uniform int TextureMode;\n\ uniform int ColorMode;\n\ uniform int MultiplyColor;\n\ uniform int SampleAmount;\n\ uniform int UseNormal;\n\ uniform int InputColorSpace;\n\ uniform int OutputColorSpace;\n\ uniform int ShowStripes;\n\ uniform vec3 uViewPos;\n\ in vec4 fColor;\n\ in vec2 fUV;\n\ flat in vec3 fNormal;\n\ in vec3 fGPos;\n\ layout(location = 0) out vec4 outColor;\n\ layout(location = 1) out vec3 outNormal;\n\ layout(location = 2) out vec3 outGPos;\n\ #with TNS_SHADER_COLOR_COMMON\n\ vec3 ConvertColorSpace(vec3 color){\n\ if(InputColorSpace!=OutputColorSpace){\n\ if(ColorMode==0){\n\ if(InputColorSpace==0) color=to_linear_srgb(color);\n\ else if(InputColorSpace==1) color=to_linear_clay(color);\n\ } \n\ vec3 xyz; if(ColorMode==1){ color=okhsl_to_linear_srgb(color); }\n\ if(InputColorSpace==1){ xyz=Clay2XYZ(color); }\n\ if(InputColorSpace==0){ xyz=sRGB2XYZ(color); }\n\ if(OutputColorSpace==0){ color=to_log_srgb(XYZ2sRGB(xyz)); }\n\ if(OutputColorSpace==1){ color=to_log_clay(XYZ2Clay(xyz)); }\n\ }else{\n\ if(ColorMode==1){ color=okhsl_to_srgb(color); }\n\ else if(ColorMode==0){ color=color; }\n\ else{\n\ if(OutputColorSpace==0){ color=to_log_srgb(color); }\n\ if(OutputColorSpace==1){ color=to_log_clay(color); }\n\ }\n\ }\n\ if(ShowStripes!=0){\n\ if(color.r>1.00001||color.g>1.00001||color.b>1.00001||color.r<0||color.g<0||color.b<0){ color=mix(color,vec3(0.5,0.5,0.5),(sin((gl_FragCoord.x+gl_FragCoord.y)/2)>0)?1:0.5); }\n\ }\n\ return color;\n\ }\n\ void main(){\n\ vec4 color=vec4(1,0,1,1);\n\ if(TextureMode==0){ color = fColor;}\n\ else if(TextureMode==1){color = vec4(fColor.rgb,fColor.a*texture2D(TexColor,fUV.st).r);}\n\ else if(TextureMode==2){\n\ color=texture2D(TexColor,fUV.st);\n\ if(MultiplyColor!=0){color*=fColor;}\n\ }else if(TextureMode==3){\n\ color=vec4(0,0,0,0);\n\ ivec2 texSize = textureSize(TexColorMS);\n\ for(int i=0;i0){ factor=0; }\n\ color=vec4(color.rgb*mix(0.2,1.,factor),color.a);\n\ vec3 oNormal=fNormal; if(view<0){ oNormal=-fNormal; }\n\ outNormal = oNormal;\n\ }\n\ color=vec4(ConvertColorSpace(color.rgb),color.a); color.a=clamp(color.a,0,1);\n\ outColor = color; \n\ outGPos = fGPos;\n\ }"; const char LA_RAY_VERTEX_SHADER[] = "#version 330\n\ in vec3 vUV;\n\ in vec4 vVertex;\n\ out vec3 fViewDir;\n\ void main(){\n\ gl_Position=vVertex;\n\ fViewDir = vUV;\n\ }"; #define LA_SHADER_LIB_FXAA \ "#define DIFF_LUM_ABS_HOLD 0.0833 \n\ #define DIFF_LUM_RES_HOLD 0.166\n\ float luminance(vec3 col) {\n\ return dot(col, vec3(0.2126729f, 0.7151522f, 0.0721750f));\n\ }\n\ vec4 fxaa(in sampler2D tex, vec2 uv, vec2 texsize) {\n\ vec3 e = vec3(-1., 1., 0.);\n\ vec2 offuv = uv;\n\ vec3 colnw = texture(tex, uv + e.xy / texsize).rgb;\n\ vec3 coln = texture(tex, uv + e.zy / texsize).rgb;\n\ vec3 colne = texture(tex, uv + e.yy / texsize).rgb;\n\ vec3 colw = texture(tex, uv + e.xz / texsize).rgb;\n\ vec4 colm4 = texture(tex, uv + e.zz / texsize);\n\ vec3 colm = colm4.rgb;\n\ vec3 cole = texture(tex, uv + e.yz / texsize).rgb;\n\ vec3 colsw = texture(tex, uv + e.xx / texsize).rgb;\n\ vec3 cols = texture(tex, uv + e.zx / texsize).rgb;\n\ vec3 colse = texture(tex, uv + e.yx / texsize).rgb;\n\ float lnw = luminance(colnw), ln = luminance(coln), lne = luminance(colne),\n\ lw = luminance(colw), lm = luminance(colm), le = luminance(cole),\n\ lsw = luminance(colsw), ls = luminance(cols), lse = luminance(colse);\n\ float maxl = max(ln, max(ls, max(lw, max(le, lm))));\n\ float minl = min(ln, min(ls, min(lw, min(le, lm))));\n\ float diff = maxl - minl;\n\ if (diff < max(DIFF_LUM_ABS_HOLD, DIFF_LUM_RES_HOLD * maxl)) return colm4;\n\ float filterfactor = 0.;\n\ filterfactor += 2. * (ln + lw + ls + le) + lnw + lne + lsw + lse;\n\ filterfactor /= 12.;\n\ filterfactor = abs(filterfactor - lm);\n\ filterfactor = clamp(filterfactor / diff, 0., 1.);\n\ float blend = smoothstep(0., 1., filterfactor);\n\ blend *= blend;\n\ float hedge = 2.*(ln + ls - 2.*lm) + (lne + lse - 2.*le) + (lnw + lsw - 2.*lw);\n\ float vedge = 2.*(le + lw - 2.*lm) + (lne + lnw - 2.*ln) + (lse + lsw - 2.*ls);\n\ float ish = step(vedge, hedge);\n\ float psoff = ish >= 1.0 ? 1./texsize.y : 1./texsize.x;\n\ float pleft = ish >= 1.0 ? ln : le;\n\ float pright = ish >= 1.0 ? ls : lw;\n\ if (abs(pleft - lm) < abs(pright - lm)) psoff = -psoff;\n\ if (ish >= 1.0) { offuv.y += psoff * blend; }else{ offuv.x += psoff * blend; }\n\ return vec4(texture(tex, offuv).rgb,colm4.a); \n\ }\n" const char LA_RAY_FRAGMENT_SHADER[] = "#version 330\n\ uniform vec3 uViewDir;\n\ uniform vec3 uViewPos;\n\ uniform float uFOV;\n\ in vec3 fViewDir;\n\ uniform sampler2D TexColor;\n\ uniform sampler2D TexNormal;\n\ uniform sampler2D TexGPos;\n" LA_SHADER_LIB_FXAA "void main(){\n\ float d=dot(uViewDir,normalize(fViewDir));\n\ float target=cos(uFOV/2.);\n\ vec4 color=vec4(1.,1.,1.,1.); float mul=0.;\n\ if(d<(target+0.005)&&d>target) mul=1.0;\n\ vec2 uv=gl_FragCoord.xy/textureSize(TexColor,0);\n\ vec4 buffer_color=fxaa(TexColor,uv,textureSize(TexColor,0));\n\ //vec4 buffer_color=texture2D(TexColor,uv);\n\ gl_FragColor = mul*color+buffer_color;\n\ }"; const char LA_SCENE_VERTEX_SHADER[] = "#version 330\n\ uniform mat4 mProjection;\n\ uniform mat4 mModel;\n\ uniform mat4 mView;\n\ uniform mat4 mShadow;\n\ in vec4 vVertex;\n\ in vec4 vColor;\n\ in vec4 vNormal;\n\ in vec2 vUV;\n\ out vec4 fColor;\n\ //out vec4 fNormal;\n\ out vec2 fUV;\n\ out vec4 fGPos;\n\ void main(){\n\ gl_Position= mProjection * mView * mModel * vVertex;\n\ fUV=vUV;\n\ //fNormal=vNormal;\n\ fColor=vColor;\n\ fGPos= mShadow * mModel * vVertex;\ }"; const char LA_SCENE_FRAGMENT_SHADER[] = "#version 330\n\ uniform sampler2D TexColor;\n\ uniform sampler2DMS TexColorMS;\ uniform int TextureMode;\n\ uniform int SampleAmount;\n\ uniform int MultiplyColor;\n\ in vec4 fColor;\n\ //in vec4 fNormal;\n\ in vec2 fUV;\n\ in vec4 fGPos;\n\ vec4 GetTexture(vec2 uv){\n\ vec4 color=vec4(1,0,1,1);\n\ if(TextureMode==1 || TextureMode==2){ return texture2D(TexColor,uv); }\n\ else if(TextureMode==3){\n\ ivec2 texSize = textureSize(TexColorMS);\n\ for(int i=0;i (closestDepth+0.001) ? 0.5 : 1.0;\n\ return shadow;\n\ }\n\ void main(){\n\ gl_FragColor=GetShadow(fGPos)*fColor;\n\ }"; const char LA_CASCADE_SHADOW_VERTEX_SHADER[] = "#version 330\n\ in vec4 vVertex;\n\ uniform mat4 mModel;\n\ uniform mat4 mShadow;\n\ void main(){\n\ gl_Position=mShadow*mModel*vVertex;\n\ }"; const char LA_CASCADE_SHADOW_FRAGMENT_SHADER[] = "#version 330\nvoid main(){gl_FragDepth = gl_FragCoord.z;}"; const char LA_SELECTION_VERTEX_SHADER[] = "#version 330\n\ in vec4 vVertex;\n\ in vec3 vColor;\n\ uniform mat4 mProjection;\n\ uniform mat4 mModel;\n\ uniform mat4 mView;\n\ flat out vec3 fIdColor;\n\ void main(){\n\ gl_Position = mProjection * mView * mModel * vVertex;\n\ fIdColor = vColor;\n\ }"; const char LA_SELECTION_FRAGMENT_SHADER[] = "#version 330\n\ flat in vec3 fIdColor;\n\ void main(){\n\ gl_FragColor=vec4(fIdColor,1.);\n\ }"; int tKnlAttatchShader(tnsShader *tns); tnsShader *tKnlFindShader1i(int CustomIndex); void tKnlPushMatrix(); void tKnlPopMatrix(); laListHandle *tKnlGetTextureList(); void tnsLoadIdentity44d(tnsMatrix44d m); void tnsMakeOrthoMatrix44d(tnsMatrix44d mProjection, real xMin, real xMax, real yMin, real yMax, real zMin, real zMax); void tnsMakePerspectiveMatrix44d(tnsMatrix44d mProjection, real fFov_rad, real fAspect, real zMin, real zMax); void tnsMakeTranslationMatrix44d(tnsMatrix44d mTrans, real x, real y, real z); void tnsMakeRotationMatrix44d(tnsMatrix44d m, real angle_rad, real x, real y, real z); void tnsMakeScaleMatrix44d(tnsMatrix44d m, real x, real y, real z); void tnsMultiply44d(tnsMatrix44d result, tnsMatrix44d l, tnsMatrix44d r); void tnsInitFirstLevel(tnsMatrixStack *tms); tnsMatrixStackItem *tKnlGetCurrentMatStackItem(); tnsShader *tKnlGetActiveShader(); void tnsAttach2DOffscreenBuffer(tnsOffscreen *target, GLuint attatchment, tnsTexture *use); void tnsDetach2DOffscreenBuffer(tnsOffscreen *target, GLuint which_attach_point); //========================================================================================= tnsMain *T; real DefaultZRange[2] = {0.1, 1000}; //=======================================[SYS] extern LA MAIN; void InitGLRenderEnviornment(){ glEnable(GL_SCISSOR_TEST); }; void tnsSwitchToCurrentWindowContext(void *wnd){ //HGLRC current = wglGetCurrentContext(), hglrc = wnd->SystemGLRC; //HDC hdc = wnd->SystemDC; // ////if (hglrc != current) //int a = GetLastError(); // //int s = wglMakeCurrent(hdc, hglrc); laWindow* win = wnd; glXMakeContextCurrent(MAIN.dpy, win->win, win->win, MAIN.glc); }; void tnsViewportWithScissor(int x, int y, int w, int h){ tnsShader *current_shader = 0; glEnable(GL_SCISSOR_TEST); glViewport(x, y, w, h); glScissor(x, y, w, h); if ((current_shader = tKnlGetActiveShader())){ tnsResetViewMatrix(); tnsShaderApplyView(current_shader, tnsGetViewMatrix()); tnsResetModelMatrix(); tnsShaderApplyModel(current_shader, tnsGetModelMatrix()); } } void tnsViewport(int x, int y, int w, int h){ glViewport(x, y, w, h); } //Must At Origion! //void UseWindowMatrix_WithScissor(laWndPlacement* wp){ // tnsViewportWithScissor(0, 0, VAL2_CLIENT_W_H(*wp)); // SetMatrix2Di(0, VAL2_CLIENT_W_H(*wp), 0); //}; //void UseBlockMatrix_WithScissor(laBlockPlacement* bp){ // tnsViewportWithScissor(bp->UpperLeftX, // bp->ClientHeight - bp->LowerRightY, // bp->LowerRightX - bp->UpperLeftX, // bp->LowerRightY - bp->UpperLeftY); // SetMatrix2Di(0, bp->LowerRightX - bp->UpperLeftX, // 0, bp->UpperLeftY - bp->LowerRightY); //}; void DrawWireRect2dp(real x, real y, real x2, real y2){ real Verts[8]; tnsMakeQuad2d(Verts, x, y, x2, y, x2, y2, x, y2); tnsVertexArray2d(Verts, 4); tnsPackAs(GL_LINE_LOOP); }; void DrawWireRect4ds(real x, real y, real w, real h){ real Verts[8]; tnsMakeQuad2d(Verts, x, y, x + w, y, x + w, y + h, x, y + h); tnsVertexArray2d(Verts, 4); tnsPackAs(GL_LINE_LOOP); }; void DrawWireRect4drs(real x, real y, real w, real h){ real Verts[8]; tnsMakeQuad2d(Verts, x, y, x + w, y, x + w, y - h, x, y - h); tnsVertexArray2d(Verts, 4); tnsPackAs(GL_LINE_LOOP); }; void DrawSoildRect4drs(real x, real y, real w, real h){ real Verts[8]; tnsMakeQuad2d(Verts, x, y, x + w, y, x + w, y - h, x, y - h); tnsVertexArray2d(Verts, 4); tnsPackAs(GL_TRIANGLE_FAN); } void DrawWireCross4ds(real x, real y, real w, real h){ real Verts[8]; tnsMakeQuad2d(Verts, x, y, x + w, y + h, x + w, y, x, y + h); tnsVertexArray2d(Verts, 4); tnsPackAs(GL_LINES); }; void DrawWireCross4drs(real x, real y, real w, real h){ real Verts[8]; tnsMakeQuad2d(Verts, x, y, x + w, y - h, x + w, y, x, y - h); tnsVertexArray2d(Verts, 4); tnsPackAs(GL_LINES); }; void DrawGrid6f(real L, real R, real U, real B, real stepX, real stepY){ //do nothing; } void DrawSolidArrow1i3d(int direction, real xoff, real yoff, real size){ real size_2 = size / 2.0f; real Verts[6]; switch (direction){ case TNS_ARROW_L: tnsMakeTriangle(Verts, xoff + size_2, yoff, xoff, yoff - size_2, xoff + size_2, yoff - size); break; case TNS_ARROW_R: tnsMakeTriangle(Verts, xoff, yoff, xoff + size_2, yoff - size_2, xoff, yoff - size); break; } tnsPackAs(GL_TRIANGLES); } //=======================================[Shader] int tnsNextPowOf2(int i){ int result = 2; while (result < i){ result *= 2; } return result; } void tnsShaderMakeIndex(tnsShader *tns){ int program; if (!tns) return; program = tns->glProgramID; tns->iModel = glGetUniformLocation(program, "mModel"); tns->iProjection = glGetUniformLocation(program, "mProjection"); tns->iProjectionInverse = glGetUniformLocation(program, "mProjectionInverse"); tns->iView = glGetUniformLocation(program, "mView"); //tns->iNormal = glGetUniformLocation(program, "mNormalScaler"); tns->iShadow = glGetUniformLocation(program, "mShadow"); tns->iVertex = glGetAttribLocation(program, "vVertex"); tns->iNormal = glGetAttribLocation(program, "vNormal"); tns->iColor = glGetAttribLocation(program, "vColor"); tns->iUV = glGetAttribLocation(program, "vUV"); tns->iTexColor = glGetUniformLocation(program, "TexColor"); tns->iTexNormal = glGetUniformLocation(program, "TexNormal"); tns->iTexGPos = glGetUniformLocation(program, "TexGPos"); tns->iTexColorMS = glGetUniformLocation(program, "TexColorMS"); tns->iMultiplyColor = glGetUniformLocation(program, "MultiplyColor"); tns->iTextureMode = glGetUniformLocation(program, "TextureMode"); tns->iColorMode = glGetUniformLocation(program, "ColorMode"); tns->iSampleAmount = glGetUniformLocation(program, "SampleAmount"); tns->iUseNormal = glGetUniformLocation(program, "UseNormal"); tns->iOutputColorSpace=glGetUniformLocation(program, "OutputColorSpace"); tns->iInputColorSpace=glGetUniformLocation(program, "InputColorSpace"); tns->iShowStripes=glGetUniformLocation(program, "ShowStripes"); if(tns->iTexColor>=0){glUniform1i(tns->iTexColor, 0);} if(tns->iTexColorMS>=0){glUniform1i(tns->iTexColorMS, 1);} tns->uViewDir = glGetUniformLocation(program, "uViewDir"); tns->uViewPos = glGetUniformLocation(program, "uViewPos"); tns->uFOV = glGetUniformLocation(program, "uFOV"); } void tnsShaderApplyProjection(tnsShader *tns, tnsMatrix44d m){ tnsMatrix44f mf; if (T->BindedShader != tns){ glUseProgram(tns->glProgramID); T->BindedShader = tns; } tnsConvert44df(m, mf); glUniformMatrix4fv(tns->iProjection, 1, 0, mf); } void tnsShaderApplyProjectionInverse(tnsShader *tns, tnsMatrix44d m){ tnsMatrix44f mf; tnsMatrix44d i; if (T->BindedShader != tns){ glUseProgram(tns->glProgramID); T->BindedShader = tns; } tnsInverse44d(i, m); tnsConvert44df(i, mf); glUniformMatrix4fv(tns->iProjectionInverse, 1, 0, mf); } void tnsShaderApplyModel(tnsShader *tns, tnsMatrix44d m){ tnsMatrix44f mf; if (T->BindedShader != tns){ glUseProgram(tns->glProgramID); T->BindedShader = tns; } tnsConvert44df(m, mf); glUniformMatrix4fv(tns->iModel, 1, 0, mf); } void tnsShaderApplyView(tnsShader *tns, tnsMatrix44d m){ tnsMatrix44f mf; if (T->BindedShader != tns){ glUseProgram(tns->glProgramID); T->BindedShader = tns; } tnsConvert44df(m, mf); glUniformMatrix4fv(tns->iView, 1, 0, mf); } void tnsShaderApplyNormalScaler(tnsShader *tns, tnsMatrix44d m){ tnsMatrix44f mf; if (tns->iNormal == -1) return; if (T->BindedShader != tns){ glUseProgram(tns->glProgramID); T->BindedShader = tns; } tnsConvert44df(m, mf); glUniformMatrix4fv(tns->iNormal, 1, 0, mf); } void tnsShaderApplyShadowMatrix(tnsShader *tns, tnsMatrix44d m){ tnsMatrix44f mf; if (tns->iShadow == -1) return; if (T->BindedShader != tns){ glUseProgram(tns->glProgramID); T->BindedShader = tns; } tnsConvert44df(m, mf); glUniformMatrix4fv(tns->iShadow, 1, 0, mf); } char* tnsEnsureShaderCommoms(char* Content){ return strSub(Content,"#with TNS_SHADER_COLOR_COMMON",TNS_SHADER_COLOR_COMMON); } int tnsNewVertexShader(char *Content){ int status = 0; char error[1024]; GLuint VertexShaderObject; tnsShader *s = 0; if (!Content) return -1; VertexShaderObject = glCreateShader(GL_VERTEX_SHADER); char* UseContent=tnsEnsureShaderCommoms(Content); glShaderSource(VertexShaderObject, 1, &UseContent, 0); free(UseContent); glCompileShader(VertexShaderObject); glGetShaderiv(VertexShaderObject, GL_COMPILE_STATUS, &status); if (status == GL_FALSE){ glGetShaderInfoLog(VertexShaderObject, sizeof(error), 0, error); printf("Vertex shader error:\n%s", error); glDeleteShader(VertexShaderObject); return -1; } return VertexShaderObject; } int tnsNewFragmentShader(char *Content){ int status = 0; char error[1024]; GLuint FragmentShaderObject; tnsShader *s = 0; if (!Content) return -1; FragmentShaderObject = glCreateShader(GL_FRAGMENT_SHADER); char* UseContent=tnsEnsureShaderCommoms(Content); glShaderSource(FragmentShaderObject, 1, &UseContent, 0); free(UseContent); glCompileShader(FragmentShaderObject); glGetShaderiv(FragmentShaderObject, GL_COMPILE_STATUS, &status); if (status == GL_FALSE){ glGetShaderInfoLog(FragmentShaderObject, sizeof(error), 0, error); printf("Fragment shader error:\n%s", error); glDeleteShader(FragmentShaderObject); return -1; } return FragmentShaderObject; } int tnsNewGeometryShader(char *Content){ int status = 0; char error[1024]; GLuint GeometryShaderObject; tnsShader *s = 0; if (!Content) return -1; GeometryShaderObject = glCreateShader(GL_GEOMETRY_SHADER); char* UseContent=tnsEnsureShaderCommoms(Content); glShaderSource(GeometryShaderObject, 1, &UseContent, 0); free(UseContent); glCompileShader(GeometryShaderObject); glGetShaderiv(GeometryShaderObject, GL_COMPILE_STATUS, &status); if (status == GL_FALSE){ glGetShaderInfoLog(GeometryShaderObject, sizeof(error), 0, error); printf("Geometry shader error:\n%s", error); glDeleteShader(GeometryShaderObject); return -1; } return GeometryShaderObject; } tnsShader *tnsNewShaderProgram(int VertexShaderID, int FragmentShaderID, int GeometryShaderID){ int vso = VertexShaderID; int fso = FragmentShaderID; int gso = GeometryShaderID; tnsShader *tns = 0; int status = 0; char error[1024]; if (!vso || !fso) return 0; tns = CreateNew(tnsShader); tns->vtShaderID = vso; tns->fgShaderID = fso; tns->glProgramID = glCreateProgram(); glAttachShader(tns->glProgramID, vso); glAttachShader(tns->glProgramID, fso); if (GeometryShaderID > -1){ glAttachShader(tns->glProgramID, gso); tns->gsShaderID=gso; } glLinkProgram(tns->glProgramID); glGetProgramiv(tns->glProgramID, GL_LINK_STATUS, &status); if (status == GL_FALSE){ glGetProgramInfoLog(tns->glProgramID, sizeof(error), 0, error); printf("Shader Linking error:\n%s", error); glDetachShader(tns->glProgramID, vso); glDetachShader(tns->glProgramID, fso); glDeleteShader(vso); glDeleteShader(fso); glDeleteProgram(tns->glProgramID); FreeMem(tns); return 0; } glUseProgram(tns->glProgramID); tnsShaderMakeIndex(tns); return tns; } int tnsEnableShader(int index){ tnsMatrixStackItem *tmsi; tnsShader *tns = tKnlFindShader1i(index); if (!tns){ glUseProgram(0); T->CurrentShader = 0; T->BindedShader = 0; return 0; } glUseProgram(tns->glProgramID); T->CurrentShader = tns; T->BindedShader = tns; tmsi = tKnlGetCurrentMatStackItem(); tnsShaderApplyProjection(tns, tmsi->projection); tnsShaderApplyView(tns, tmsi->view); tnsShaderApplyModel(tns, tmsi->model); tnsUseShader(tns); return 1; } int tnsEnableShaderv(tnsShader *shader){ tnsMatrixStackItem *tmsi; tnsShader *tns = shader; if (!tns){ glUseProgram(0); T->CurrentShader = 0; T->BindedShader = 0; return 0; } glUseProgram(tns->glProgramID); T->CurrentShader = tns; T->BindedShader = tns; tmsi = tKnlGetCurrentMatStackItem(); tnsShaderApplyProjection(tns, tmsi->projection); tnsShaderApplyProjectionInverse(tns, tmsi->projection); tnsShaderApplyView(tns, tmsi->view); tnsShaderApplyModel(tns, tmsi->model); tnsUseShader(tns); //if (tns->iVertex != -1) glEnableVertexAttribArray(tns->iVertex); //if (tns->iColor != -1) glEnableVertexAttribArray(tns->iColor); //if (tns->iNormal != -1) glEnableVertexAttribArray(tns->iNormal); //if (tns->iUV != -1) glEnableVertexAttribArray(tns->iUV); return 1; } int tnsUseShader(tnsShader *shader){ T->StateShader = shader; } void tnsDeleteShaderProgram(tnsShader* s){ tnsUseShader(0); tnsEnableShaderv(0); if(s->vtShaderID>-1) glDeleteShader(s->vtShaderID); if(s->fgShaderID>-1) glDeleteShader(s->fgShaderID); if(s->gsShaderID>-1) glDeleteShader(s->gsShaderID); glDeleteProgram(s->glProgramID); free(s); } void tnsUseImmShader(){ T->StateShader = T->immShader; } void tnsUseTransparentGridShader(){ T->StateShader = T->TransparentGridShader; } void tnsUseExtraBufferShader(){ T->StateShader = T->ExtraBuffersShader; } void tnsUseRayShader(){ T->StateShader = T->RayShader; } void tnsUseShadowShader(){ T->StateShader = T->ShadowShader; } void tnsUseSceneShader(){ T->StateShader = T->SceneShader; } //=======================================[MAT] int tnsLineIntersectTest2d(tnsVector2d a1, tnsVector2d a2, tnsVector2d b1, tnsVector2d b2, double *aRatio){ double k1, k2; double x; double y; double Ratio; double xDiff = (a2[0] - a1[0]); // +DBL_EPSILON; double xDiff2 = (b2[0] - b1[0]); if (xDiff == 0){ if (xDiff2 == 0){ *aRatio = 0; return 0; } double r2 = tnsGetRatiod(b1[0], b2[0], a1[0]); y = tnsLinearItp(b1[1], b2[1], r2); *aRatio = Ratio = tnsGetRatiod(a1[1], a2[1], y); }else{ if (xDiff2 == 0){ Ratio = tnsGetRatiod(a1[0], a2[0], b1[0]); //y = tnsLinearItp(a1[1], a2[1], r2); *aRatio = Ratio; }else{ k1 = (a2[1] - a1[1]) / xDiff; k2 = (b2[1] - b1[1]) / xDiff2; if ((k1 == k2)) return 0; x = (a1[1] - b1[1] - k1 * a1[0] + k2 * b1[0]) / (k2 - k1); Ratio = (x - a1[0]) / xDiff; *aRatio = Ratio; } } if (b1[0] == b2[0]){ y = tnsLinearItp(a1[1], a2[1], Ratio); if (y > TNS_MAX2(b1[1], b2[1]) || y < TNS_MIN2(b1[1], b2[1])) return 0; }else if (Ratio <= 0 || Ratio > 1 || (b1[0] > b2[0] && x > b1[0]) || (b1[0] < b2[0] && x < b1[0]) || (b2[0] > b1[0] && x > b2[0]) || (b2[0] < b1[0] && x < b2[0])) return 0; return 1; } double tnsGetLineZ(tnsVector3d L, tnsVector3d R, real Ratio){ //double z = 1 / tnsLinearItp(1 / L[2], 1 / R[2], Ratio); double z = tnsLinearItp(L[2], R[2], Ratio); return z; } double tnsGetLineZPoint(tnsVector3d L, tnsVector3d R, tnsVector3d FromL){ double r = (FromL[0] - L[0]) / (R[0] - L[0]); return tnsLinearItp(L[2], R[2], r); //return 1 / tnsLinearItp(1 / L[2], 1 / R[2], r); } double tnsGetRatio3d(tnsVector3d L, tnsVector3d R, tnsVector3d FromL){ double r = (FromL[0] - L[0]) / (R[0] - L[0]); return r; } double tnsGetRatiod(real L, real R, real FromL){ double r = (FromL - L) / (R - L); return r; } real tnsInterpolate(real L, real R, real T){ return tnsLinearItp(L, R, T); } void tnsInterpolate2dv(real *L, real *R, real T, real *Result){ Result[0] = tnsLinearItp(L[0], R[0], T); Result[1] = tnsLinearItp(L[1], R[1], T); } void tnsInterpolate3dv(real *L, real *R, real T, real *Result){ Result[0] = tnsLinearItp(L[0], R[0], T); Result[1] = tnsLinearItp(L[1], R[1], T); Result[2] = tnsLinearItp(L[2], R[2], T); } void tnsInterpolateTripple2d(tnsVector2d v1, tnsVector2d v2, tnsVector2d v3, real ratio, tnsVector2d result){ tnsVector2d i1,i2; tnsInterpolate2dv(v1,v2,ratio,i1); tnsInterpolate2dv(v2,v3,ratio,i2); tnsInterpolate2dv(i1,i2,ratio,result); } void tnsVectorMinus2d(tnsVector2d result, tnsVector2d l, tnsVector2d r){ result[0] = l[0] - r[0]; result[1] = l[1] - r[1]; } void tnsVectorMinus3d(tnsVector3d result, tnsVector3d l, tnsVector3d r){ result[0] = l[0] - r[0]; result[1] = l[1] - r[1]; result[2] = l[2] - r[2]; } void tnsVectorSubtract3d(tnsVector3d l, tnsVector3d r){ l[0] = l[0] - r[0]; l[1] = l[1] - r[1]; l[2] = l[2] - r[2]; } void tnsVectorPlus3d(tnsVector3d result, tnsVector3d l, tnsVector3d r){ result[0] = l[0] + r[0]; result[1] = l[1] + r[1]; result[2] = l[2] + r[2]; } void tnsVectorAccum3d(tnsVector3d l, tnsVector3d r){ l[0] = l[0] + r[0]; l[1] = l[1] + r[1]; l[2] = l[2] + r[2]; } void tnsVectorAccum2d(tnsVector2d l, tnsVector2d r){ l[0] = l[0] + r[0]; l[1] = l[1] + r[1]; } void tnsVectorNegate3d(tnsVector3d result, tnsVector3d l){ result[0] = -l[0]; result[1] = -l[1]; result[2] = -l[2]; } void tnsVectorNegateSelf3d(tnsVector3d l){ l[0] = -l[0]; l[1] = -l[1]; l[2] = -l[2]; } void tnsVectorCopy2d(tnsVector2d from, tnsVector2d to){ to[0] = from[0]; to[1] = from[1]; } void tnsVectorCopy3d(tnsVector3d from, tnsVector3d to){ to[0] = from[0]; to[1] = from[1]; to[2] = from[2]; } void tnsVectorCopy4d(tnsVector4d from, tnsVector4d to){ to[0] = from[0]; to[1] = from[1]; to[2] = from[2]; to[3] = from[3]; } void tnsVectorMultiSelf4d(tnsVector4d from, real num){ from[0] *= num; from[1] *= num; from[2] *= num; from[3] *= num; } void tnsVectorMultiSelf3d(tnsVector3d from, real num){ from[0] *= num; from[1] *= num; from[2] *= num; } void tnsVectorMultiSelf2d(tnsVector2d from, real num){ from[0] *= num; from[1] *= num; } void tnsVectorMulti4d(tnsVector4d to, tnsVector4d from, real num){ to[0]=from[0]*num; to[1]=from[1]*num; to[2]=from[2]*num; to[3]=from[3]*num; } void tnsVectorMulti3d(tnsVector3d to, tnsVector3d from, real num){ to[0]=from[0]*num; to[1]=from[1]*num; to[2]=from[2]*num; } void tnsVectorMulti2d(tnsVector2d to, tnsVector2d from, real num){ to[0]=from[0]*num; to[1]=from[1]*num; } real tnsDirectionToRad(tnsVector2d Dir){ real arcc = acos(Dir[0]); real arcs = asin(Dir[1]); if (Dir[0] >= 0){ if (Dir[1] >= 0) return arcc; else return TNS_PI * 2 - arcc; }else{ if (Dir[1] >= 0) return arcs + TNS_PI / 2; else return TNS_PI + arcs; } } void tnsConvert44df(tnsMatrix44d from, tnsMatrix44f to){ to[0] = from[0]; to[1] = from[1]; to[2] = from[2]; to[3] = from[3]; to[4] = from[4]; to[5] = from[5]; to[6] = from[6]; to[7] = from[7]; to[8] = from[8]; to[9] = from[9]; to[10] = from[10]; to[11] = from[11]; to[12] = from[12]; to[13] = from[13]; to[14] = from[14]; to[15] = from[15]; } void tnsLoadIdentity44d(tnsMatrix44d m){ memset(m, 0, sizeof(tnsMatrix44d)); m[0] = 1.0f; m[5] = 1.0f; m[10] = 1.0f; m[15] = 1.0f; }; real tnsDistIdv2(real x1, real y1, real x2, real y2){ real x = x2 - x1, y = y2 - y1; return sqrt((x * x + y * y)); } real tnsDist3dv(tnsVector3d l, tnsVector3d r){ real x = r[0] - l[0]; real y = r[1] - l[1]; real z = r[2] - l[2]; return sqrt(x * x + y * y + z * z); } real tnsDist2dv(tnsVector2d l, tnsVector2d r){ real x = r[0] - l[0]; real y = r[1] - l[1]; return sqrt(x * x + y * y); } real tnsLength3d(tnsVector3d l){ return (sqrt(l[0] * l[0] + l[1] * l[1] + l[2] * l[2])); } real tnsLength2d(tnsVector3d l){ return (sqrt(l[0] * l[0] + l[1] * l[1])); } void tnsNormalize3d(tnsVector3d result, tnsVector3d l){ real r = sqrt(l[0] * l[0] + l[1] * l[1] + l[2] * l[2]); result[0] = l[0] / r; result[1] = l[1] / r; result[2] = l[2] / r; } void tnsNormalize2d(tnsVector2d result, tnsVector2d l){ real r = sqrt(l[0] * l[0] + l[1] * l[1]); result[0] = l[0] / r; result[1] = l[1] / r; } void tnsNormalizeSelf2d(tnsVector3d result){ real r = sqrt(result[0] * result[0] + result[1] * result[1]); result[0] /= r; result[1] /= r; } void tnsNormalizeSelf3d(tnsVector3d result){ real r = sqrt(result[0] * result[0] + result[1] * result[1] + result[2] * result[2]); result[0] /= r; result[1] /= r; result[2] /= r; } real tnsDot3d(tnsVector3d l, tnsVector3d r, int normalize){ tnsVector3d ln, rn; if (normalize){ tnsNormalize3d(ln, l); tnsNormalize3d(rn, r); return (ln[0] * rn[0] + ln[1] * rn[1] + ln[2] * rn[2]); } return (l[0] * r[0] + l[1] * r[1] + l[2] * r[2]); } real tnsDot2d(tnsVector2d l, tnsVector2d r, int normalize){ tnsVector3d ln, rn; if (normalize){ tnsNormalize2d(ln, l); tnsNormalize2d(rn, r); return (ln[0] * rn[0] + ln[1] * rn[1]); } return (l[0] * r[0] + l[1] * r[1]); } real tnsVectorCross3d(tnsVector3d result, tnsVector3d l, tnsVector3d r){ result[0] = l[1] * r[2] - l[2] * r[1]; result[1] = l[2] * r[0] - l[0] * r[2]; result[2] = l[0] * r[1] - l[1] * r[0]; return tnsLength3d(result); } void tnsVectorCrossOnly3d(tnsVector3d result, tnsVector3d l, tnsVector3d r){ result[0] = l[1] * r[2] - l[2] * r[1]; result[1] = l[2] * r[0] - l[0] * r[2]; result[2] = l[0] * r[1] - l[1] * r[0]; } real tnsAngleRad3d(tnsVector3d from, tnsVector3d to, tnsVector3d PositiveReference){ if (PositiveReference){ tnsVector3d res; tnsVectorCross3d(res, from, to); if (tnsDot3d(res, PositiveReference, 1) > 0) return acosf(tnsDot3d(from, to, 1)); else return -acosf(tnsDot3d(from, to, 1)); } return acosf(tnsDot3d(from, to, 1)); } void tnsApplyRotation33d(tnsVector3d result, tnsMatrix44d mat, tnsVector3d v){ result[0] = mat[0] * v[0] + mat[1] * v[1] + mat[2] * v[2]; result[1] = mat[3] * v[0] + mat[4] * v[1] + mat[5] * v[2]; result[2] = mat[6] * v[0] + mat[7] * v[1] + mat[8] * v[2]; } void tnsApplyRotation43d(tnsVector3d result, tnsMatrix44d mat, tnsVector3d v){ result[0] = mat[0] * v[0] + mat[1] * v[1] + mat[2] * v[2]; result[1] = mat[4] * v[0] + mat[5] * v[1] + mat[6] * v[2]; result[2] = mat[8] * v[0] + mat[9] * v[1] + mat[10] * v[2]; } void tnsApplyTransform43d(tnsVector3d result, tnsMatrix44d mat, tnsVector3d v){ real w; result[0] = mat[0] * v[0] + mat[4] * v[1] + mat[8] * v[2] + mat[12] * 1; result[1] = mat[1] * v[0] + mat[5] * v[1] + mat[9] * v[2] + mat[13] * 1; result[2] = mat[2] * v[0] + mat[6] * v[1] + mat[10] * v[2] + mat[14] * 1; w = mat[3] * v[0] + mat[7] * v[1] + mat[11] * v[2] + mat[15] * 1; //result[0] /= w; //result[1] /= w; //result[2] /= w; } void tnsApplyNormalTransform43d(tnsVector3d result, tnsMatrix44d mat, tnsVector3d v){ real w; result[0] = mat[0] * v[0] + mat[4] * v[1] + mat[8] * v[2] + mat[12] * 1; result[1] = mat[1] * v[0] + mat[5] * v[1] + mat[9] * v[2] + mat[13] * 1; result[2] = mat[2] * v[0] + mat[6] * v[1] + mat[10] * v[2] + mat[14] * 1; } void tnsApplyTransform44d(tnsVector4d result, tnsMatrix44d mat, tnsVector4d v){ result[0] = mat[0] * v[0] + mat[4] * v[1] + mat[8] * v[2] + mat[12] * 1; result[1] = mat[1] * v[0] + mat[5] * v[1] + mat[9] * v[2] + mat[13] * 1; result[2] = mat[2] * v[0] + mat[6] * v[1] + mat[10] * v[2] + mat[14] * 1; result[3] = mat[3] * v[0] + mat[7] * v[1] + mat[11] * v[2] + mat[15] * 1; } void tnsApplyTransform44dTrue(tnsVector4d result, tnsMatrix44d mat, tnsVector4d v){ result[0] = mat[0] * v[0] + mat[4] * v[1] + mat[8] * v[2] + mat[12] * v[3]; result[1] = mat[1] * v[0] + mat[5] * v[1] + mat[9] * v[2] + mat[13] * v[3]; result[2] = mat[2] * v[0] + mat[6] * v[1] + mat[10] * v[2] + mat[14] * v[3]; result[3] = mat[3] * v[0] + mat[7] * v[1] + mat[11] * v[2] + mat[15] * v[3]; } void tnsRemoveTranslation44d(tnsMatrix44d result, tnsMatrix44d mat){ tnsLoadIdentity44d(result); result[0] = mat[0]; result[1] = mat[1]; result[2] = mat[2]; result[4] = mat[4]; result[5] = mat[5]; result[6] = mat[6]; result[8] = mat[8]; result[9] = mat[9]; result[10] = mat[10]; } void tnsClearTranslation44d(tnsMatrix44d mat){ mat[3] = 0; mat[7] = 0; mat[11] = 0; } void tnsExtractXYZEuler44d(tnsMatrix44d mat, real *x_result, real *y_result, real *z_result){ real xRot, yRot, zRot; if (mat[2] < 1){ if (mat[2] > -1){ yRot = asin(mat[2]); xRot = atan2(-mat[6], mat[10]); zRot = atan2(-mat[1], mat[0]); }else{ yRot = -TNS_PI / 2; xRot = -atan2(-mat[4], mat[5]); zRot = 0; } }else{ yRot = TNS_PI / 2; xRot = atan2(-mat[4], mat[5]); zRot = 0; } (*x_result) = -xRot; (*y_result) = -yRot; (*z_result) = -zRot; } void tnsExtractLocation44d(tnsMatrix44d mat, real *x_result, real *y_result, real *z_result){ *x_result = mat[12]; *y_result = mat[13]; *z_result = mat[14]; } void tnsExtractUniformScale44d(tnsMatrix44d mat, real *result){ tnsVector3d v = {mat[0], mat[1], mat[2]}; *result = tnsLength3d(v); } #define L(row, col) l[(col << 2) + row] #define R(row, col) r[(col << 2) + row] #define P(row, col) result[(col << 2) + row] void tnsPrintMatrix44d(tnsMatrix44d l){ int i, j; for (i = 0; i < 4; i++){ for (j = 0; j < 4; j++){ printf("%.5f ", L(i, j)); } printf("\n"); } } void tnsCopyMatrix44d(tnsMatrix44d from, tnsMatrix44d to){ memcpy(to, from, sizeof(tnsMatrix44d)); } void tnsMultiply44d(tnsMatrix44d result, tnsMatrix44d l, tnsMatrix44d r){ int i; for (i = 0; i < 4; i++){ real ai0 = L(i, 0), ai1 = L(i, 1), ai2 = L(i, 2), ai3 = L(i, 3); P(i, 0) = ai0 * R(0, 0) + ai1 * R(1, 0) + ai2 * R(2, 0) + ai3 * R(3, 0); P(i, 1) = ai0 * R(0, 1) + ai1 * R(1, 1) + ai2 * R(2, 1) + ai3 * R(3, 1); P(i, 2) = ai0 * R(0, 2) + ai1 * R(1, 2) + ai2 * R(2, 2) + ai3 * R(3, 2); P(i, 3) = ai0 * R(0, 3) + ai1 * R(1, 3) + ai2 * R(2, 3) + ai3 * R(3, 3); } }; void tnsInverse44d(tnsMatrix44d inverse, tnsMatrix44d mat){ int i, j, k; double temp; tnsMatrix44d tempmat; real max; int maxj; tnsLoadIdentity44d(inverse); tnsCopyMatrix44d(mat, tempmat); for (i = 0; i < 4; i++){ /* Look for row with max pivot */ max = fabsf(tempmat[i * 5]); maxj = i; for (j = i + 1; j < 4; j++){ if (fabsf(tempmat[j * 4 + i]) > max){ max = fabsf(tempmat[j * 4 + i]); maxj = j; } } /* Swap rows if necessary */ if (maxj != i){ for (k = 0; k < 4; k++){ real t; t = tempmat[i * 4 + k]; tempmat[i * 4 + k] = tempmat[maxj * 4 + k]; tempmat[maxj * 4 + k] = t; t = inverse[i * 4 + k]; inverse[i * 4 + k] = inverse[maxj * 4 + k]; inverse[maxj * 4 + k] = t; } } //if (UNLIKELY(tempmat[i][i] == 0.0f)) { // return false; /* No non-zero pivot */ //} temp = (double)tempmat[i * 5]; for (k = 0; k < 4; k++){ tempmat[i * 4 + k] = (real)((double)tempmat[i * 4 + k] / temp); inverse[i * 4 + k] = (real)((double)inverse[i * 4 + k] / temp); } for (j = 0; j < 4; j++){ if (j != i){ temp = tempmat[j * 4 + i]; for (k = 0; k < 4; k++){ tempmat[j * 4 + k] -= (real)((double)tempmat[i * 4 + k] * temp); inverse[j * 4 + k] -= (real)((double)inverse[i * 4 + k] * temp); } } } } } void tnsMakeTranslationMatrix44d(tnsMatrix44d mTrans, real x, real y, real z){ tnsLoadIdentity44d(mTrans); mTrans[12] = x; mTrans[13] = y; mTrans[14] = z; } void tnsMakePerspectiveMatrix44d(tnsMatrix44d mProjection, real fFov_rad, real fAspect, real zMin, real zMax){ real yMax = zMin * tanf(fFov_rad * 0.5f); real yMin = -yMax; real xMin = yMin * fAspect; real xMax = -xMin; tnsLoadIdentity44d(mProjection); mProjection[0] = (2.0f * zMin) / (xMax - xMin); mProjection[5] = (2.0f * zMin) / (yMax - yMin); mProjection[8] = (xMax + xMin) / (xMax - xMin); mProjection[9] = (yMax + yMin) / (yMax - yMin); mProjection[10] = -((zMax + zMin) / (zMax - zMin)); mProjection[11] = -1.0f; mProjection[14] = -((2.0f * (zMax * zMin)) / (zMax - zMin)); mProjection[15] = 0.0f; } void tnsMakeZTrackingMatrix44d(tnsMatrix44d mat, tnsVector3d this, tnsVector3d that, tnsVector3d up){ tnsVector4d fwd, l, t, rt; fwd[3] = l[3] = t[3] = rt[3] = 1; t[0] = up[0]; t[1] = up[1]; t[2] = up[2]; fwd[0] = that[0] - this[0]; fwd[1] = that[1] - this[1]; fwd[2] = that[2] - this[2]; tnsNormalizeSelf3d(fwd); tnsVectorCross3d(l, fwd, t); tnsNormalizeSelf3d(l); tnsVectorCross3d(rt, l, fwd); tnsNormalizeSelf3d(rt); tnsLoadIdentity44d(mat); mat[0] = l[0]; mat[1] = l[1]; mat[2] = l[2]; mat[4] = rt[0]; mat[5] = rt[1]; mat[6] = rt[2]; mat[8] = -fwd[0]; mat[9] = -fwd[1]; mat[10] = -fwd[2]; } void tnsMakeZTrackingMatrixDelta44d(tnsMatrix44d mat, tnsVector3d delta, tnsVector3d up){ tnsVector4d fwd, l, t, rt; fwd[3] = l[3] = t[3] = rt[3] = 1; t[0] = up[0]; t[1] = up[1]; t[2] = up[2]; fwd[0] = delta[0]; fwd[1] = delta[1]; fwd[2] = delta[2]; tnsLoadIdentity44d(mat); tnsVectorCross3d(l, t, fwd); tnsVectorCross3d(rt, fwd, l); tnsNormalizeSelf3d(l); tnsNormalizeSelf3d(rt); tnsNormalizeSelf3d(fwd); mat[0] = l[0]; mat[1] = l[1]; mat[2] = l[2]; mat[4] = rt[0]; mat[5] = rt[1]; mat[6] = rt[2]; mat[8] = fwd[0]; mat[9] = fwd[1]; mat[10] = fwd[2]; } void tnsMakeOrthoMatrix44d(tnsMatrix44d mProjection, real xMin, real xMax, real yMin, real yMax, real zMin, real zMax){ tnsLoadIdentity44d(mProjection); mProjection[0] = 2.0f / (xMax - xMin); mProjection[5] = 2.0f / (yMax - yMin); mProjection[10] = -2.0f / (zMax - zMin); mProjection[12] = -((xMax + xMin) / (xMax - xMin)); mProjection[13] = -((yMax + yMin) / (yMax - yMin)); mProjection[14] = -((zMax + zMin) / (zMax - zMin)); mProjection[15] = 1.0f; } void tnsMakeRotationMatrix44d(tnsMatrix44d m, real angle_rad, real x_, real y_, real z_){ float x = x_; float y = y_; float z = z_; float c = cos(angle_rad); float s = sin(angle_rad); tnsMatrix44d d={ x*x*(1.0f-c)+c, x*y*(1.0f-c)-z*s, x*z*(1.0f-c)+y*s, 0.0f, y*x*(1.0f-c)+z*s, y*y*(1.0f-c)+c, y*z*(1.0f-c)-x*s, 0.0f, z*x*(1.0f-c)-y*s, z*y*(1.0f-c)+x*s, z*z*(1.0f-c)+c, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f }; memcpy(m,d,sizeof(tnsMatrix44d)); } void tnsMakeRotationXMatrix44d(tnsMatrix44d m, real angle_rad){ tnsLoadIdentity44d(m); m[5] = cos(angle_rad); m[6] = sin(angle_rad); m[9] = -sin(angle_rad); m[10] = cos(angle_rad); } void tnsMakeRotationYMatrix44d(tnsMatrix44d m, real angle_rad){ tnsLoadIdentity44d(m); m[0] = cos(angle_rad); m[2] = -sin(angle_rad); m[8] = sin(angle_rad); m[10] = cos(angle_rad); } void tnsMakeRotationZMatrix44d(tnsMatrix44d m, real angle_rad){ tnsLoadIdentity44d(m); m[0] = cos(angle_rad); m[1] = sin(angle_rad); m[4] = -sin(angle_rad); m[5] = cos(angle_rad); } void tnsMakeScaleMatrix44d(tnsMatrix44d m, real x, real y, real z){ tnsLoadIdentity44d(m); m[0] = x; m[5] = y; m[10] = z; } void tnsMakeViewportMatrix44d(tnsMatrix44d m, real w, real h, real Far, real Near){ tnsLoadIdentity44d(m); m[0] = w / 2; m[5] = h / 2; m[10] = (Far - Near) / 2; m[12] = w / 2; m[13] = h / 2; m[14] = (Far + Near) / 2; m[15] = 1; //m[0] = 2/w; //m[5] = 2/h; //m[10] = 1; //m[12] = 2/w; //m[13] = 2/h; //m[14] = 1; //m[15] = 1; } int tnsIntersectPlaneRay(tnsVector3d n, tnsVector3d p0, tnsVector3d l0, tnsVector3d l, real* t){ float denom = tnsDot3d(n, l, 0); if (denom > 1e-6){ tnsVector3d p0l0; tnsVectorMinus3d(p0l0,p0 ,l0); (*t) = tnsDot3d(p0l0, n, 0) / denom; return ((*t) >= 0); } return 0; } void tnsInitFirstLevel(tnsMatrixStack *tms){ tnsLoadIdentity44d(tms->level[0].model); tnsLoadIdentity44d(tms->level[0].projection); tnsLoadIdentity44d(tms->level[0].view); } //-------------------Export void tnsOrtho(real xMin, real xMax, real yMin, real yMax, real zMin, real zMax){ tnsShader *current_shader = 0; real *mat = tnsGetProjectionMatrix(); tnsMakeOrthoMatrix44d(mat, xMin, xMax, yMin, yMax, zMin, zMax); if (current_shader = tKnlGetActiveShader()){ tnsShaderApplyProjection(current_shader, mat); } } void tnsPerspective(real fFov_rad, real fAspect, real zMin, real zMax){ tnsShader *current_shader = 0; real *mat = tnsGetProjectionMatrix(); tnsMakePerspectiveMatrix44d(mat, fFov_rad, fAspect, zMin, zMax); if (current_shader = tKnlGetActiveShader()){ tnsShaderApplyProjection(current_shader, mat); } } void tnsTranslate3d(real x, real y, real z){ tnsShader *current_shader = 0; real *mat = tnsGetModelMatrix(); tnsMatrix44d transmat, result; tnsMakeTranslationMatrix44d(transmat, x, y, z); tnsMultiply44d(result, mat, transmat); memcpy(mat, result, sizeof(tnsMatrix44d)); if (current_shader = tKnlGetActiveShader()){ tnsShaderApplyModel(current_shader, result); } } void tnsPreTranslate3d(real x, real y, real z){ tnsShader *current_shader = 0; real *mat = tnsGetModelMatrix(); tnsMatrix44d transmat, result; //glTranslatef(x, y, z); tnsMakeTranslationMatrix44d(transmat, x, y, z); tnsMultiply44d(result, mat, transmat); memcpy(mat, result, sizeof(tnsMatrix44d)); } void tnsRotate4d(real degrees, real x, real y, real z){ tnsShader *current_shader = 0; real *mat = tnsGetModelMatrix(); tnsMatrix44d rotmat, result; tnsMakeRotationMatrix44d(rotmat, rad(degrees), x, y, z); tnsMultiply44d(result, mat, rotmat); memcpy(mat, result, sizeof(tnsMatrix44d)); if (current_shader = tKnlGetActiveShader()){ tnsShaderApplyModel(current_shader, result); } } void tnsPreRotate4d(real degrees, real x, real y, real z){ tnsShader *current_shader = 0; real *mat = tnsGetModelMatrix(); tnsMatrix44d rotmat, result; tnsMakeRotationMatrix44d(rotmat, rad(degrees), x, y, z); tnsMultiply44d(result, mat, rotmat); memcpy(mat, result, sizeof(tnsMatrix44d)); } void tnsScale3d(real x, real y, real z){ tnsShader *current_shader = 0; real *mat = tnsGetModelMatrix(); tnsMatrix44d scalemat, normal_scaler, result; glScalef(x, y, z); tnsMakeScaleMatrix44d(scalemat, x, y, z); tnsMultiply44d(result, mat, scalemat); memcpy(mat, result, sizeof(tnsMatrix44d)); if (current_shader = tKnlGetActiveShader()){ tnsShaderApplyModel(current_shader, result); } } void tnsPreScale3d(real x, real y, real z){ tnsShader *current_shader = 0; real *mat = tnsGetModelMatrix(); tnsMatrix44d scalemat, normal_scaler, result; glScalef(x, y, z); tnsMakeScaleMatrix44d(scalemat, x, y, z); tnsMultiply44d(result, mat, scalemat); memcpy(mat, result, sizeof(tnsMatrix44d)); } void tKnlPopMatrix(); void tKnlPushMatrix(); void tnsPushMatrix(){ tKnlPushMatrix(); }; void tnsPopMatrix(){ tKnlPopMatrix(); } //========================================[KNL] void tnsSetRayShaderUniformTextures(tnsOffscreen* doff){ if(!doff)return; tnsActiveTexture(GL_TEXTURE0); glBindTexture(doff->pColor[0]->GLTexType, doff->pColor[0]->GLTexHandle); tnsActiveTexture(GL_TEXTURE1); glBindTexture(doff->pColor[1]->GLTexType, doff->pColor[1]->GLTexHandle); tnsActiveTexture(GL_TEXTURE2); glBindTexture(doff->pColor[2]->GLTexType, doff->pColor[2]->GLTexHandle); glUniform1i(T->RayShader->iTexColor, 0); glUniform1i(T->RayShader->iTexNormal, 1); glUniform1i(T->RayShader->iTexGPos, 2); } void tnsInitRenderKernel(int matrixStackLevel){ tnsCommand *c; T = memAcquireHyper(sizeof(tnsMain)); GLuint m_nQuadVAO; T->GLVersionStr = glGetString(GL_VERSION); T->GLVendorStr = glGetString(GL_VENDOR); T->GLRendererStr = glGetString(GL_RENDERER); T->GLSLVersionStr = glGetString(GL_SHADING_LANGUAGE_VERSION); T->stack.max_level = matrixStackLevel; T->stack.level = CreateNewBuffer(tnsMatrixStackItem, matrixStackLevel); T->NextShaderIndex = 1; T->BindedShader = -1; tnsInitFirstLevel(&T->stack); /* Needed for gl3.3+ */ glGenVertexArrays(1,&T->GlobalVAO); glBindVertexArray(T->GlobalVAO); arrEnsureLength(&T->Vert, T->NextVert, &T->MaxVert, sizeof(GLfloat)); glGenBuffers(1, &T->VertBufObject); glBindBuffer(GL_ARRAY_BUFFER, T->VertBufObject); glBufferData(GL_ARRAY_BUFFER, T->MaxVert * sizeof(GLfloat), 0, GL_DYNAMIC_DRAW); arrEnsureLength(&T->Color, T->NextColor, &T->MaxColor, sizeof(GLfloat)); glGenBuffers(1, &T->ColorBufObject); glBindBuffer(GL_ARRAY_BUFFER, T->ColorBufObject); glBufferData(GL_ARRAY_BUFFER, T->MaxColor * sizeof(GLfloat), 0, GL_DYNAMIC_DRAW); arrEnsureLength(&T->Normal, T->NextNormal, &T->MaxNormal, sizeof(GLfloat)); glGenBuffers(1, &T->NormalBufObject); glBindBuffer(GL_ARRAY_BUFFER, T->NormalBufObject); glBufferData(GL_ARRAY_BUFFER, T->MaxNormal * sizeof(GLfloat), 0, GL_DYNAMIC_DRAW); arrEnsureLength(&T->TexCoord, T->NextTexCoord, &T->MaxTexCoord, sizeof(GLfloat)); glGenBuffers(1, &T->TexCoordBufObject); glBindBuffer(GL_ARRAY_BUFFER, T->TexCoordBufObject); glBufferData(GL_ARRAY_BUFFER, T->MaxTexCoord * sizeof(GLfloat), 0, GL_DYNAMIC_DRAW); arrEnsureLength(&T->Index, T->NextIndex, &T->MaxIndex, sizeof(GLuint)); glGenBuffers(1, &T->IndexBufObject); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, T->IndexBufObject); glBufferData(GL_ELEMENT_ARRAY_BUFFER, T->MaxIndex * sizeof(GLuint), 0, GL_DYNAMIC_DRAW); arrEnsureLength(&T->DrawingCommand, T->NextCommand, &T->MaxCommand, sizeof(tnsCommand)); } void tnsInitBuiltinShaders(){ T->immShader = tnsNewShaderProgram( tnsNewVertexShader(LA_IMM_VERTEX_SHADER),tnsNewFragmentShader(LA_IMM_FRAGMENT_SHADER),-1); T->TEST_MatcapShader = tnsNewShaderProgram( tnsNewVertexShader(TNS_VERTEX_SIMPLE_MATCAP), tnsNewFragmentShader(TNS_FRAGMENT_SIMPLE_MATCAP), -1); T->TransparentGridShader = tnsNewShaderProgram( tnsNewVertexShader(TNS_VERTEX_GRID), tnsNewFragmentShader(TNS_FRAGMENT_TRANSPARNT_GRID), -1); T->RayShader = tnsNewShaderProgram( tnsNewVertexShader(LA_RAY_VERTEX_SHADER), tnsNewFragmentShader(LA_RAY_FRAGMENT_SHADER), -1); T->ShadowShader = tnsNewShaderProgram( tnsNewVertexShader(LA_CASCADE_SHADOW_VERTEX_SHADER), tnsNewFragmentShader(LA_CASCADE_SHADOW_FRAGMENT_SHADER), -1); T->SceneShader = tnsNewShaderProgram( tnsNewVertexShader(LA_SCENE_VERTEX_SHADER), tnsNewFragmentShader(LA_SCENE_FRAGMENT_SHADER), -1); T->SelectionShader = tnsNewShaderProgram( tnsNewVertexShader(LA_SELECTION_VERTEX_SHADER), tnsNewFragmentShader(LA_SELECTION_FRAGMENT_SHADER), -1); tnsUseShader(T->immShader); tnsEnableShaderv(T->immShader); } void tnsInitWindowDefaultRenderConfig(){ tnsInitBuiltinShaders(); }; void tnsDeleteBuiltinShaders(){ tnsDeleteShaderProgram(T->immShader); T->immShader=0; tnsDeleteShaderProgram(T->TEST_MatcapShader); T->TEST_MatcapShader=0; tnsDeleteShaderProgram(T->TransparentGridShader); T->TransparentGridShader=0; tnsDeleteShaderProgram(T->SelectionShader); T->SelectionShader=0; tnsDeleteShaderProgram(T->SceneShader); T->SceneShader=0; tnsDeleteShaderProgram(T->ShadowShader); T->ShadowShader=0; tnsDeleteShaderProgram(T->RayShader); T->RayShader=0; } void tnsQuit(){ tnsQuitFontManager(); tnsObject*o; while(o=lstPopItem(&T->World.AllObjects)){ tnsDestroyObject(o); } while(o=lstPopItem(&T->World.RootObjects)){ tnsDestroyRootObject(o); } memFreeRemainingLeftNodes(); tnsDeleteBuiltinShaders(); tnsOffscreen* off; while(off=T->Offscreens.pFirst){ tnsDelete2DOffscreen(off); } tnsTexture* t; while(t=T->Textures.pFirst){ tnsDeleteTexture(t); } arrFree(&T->Vert, &T->MaxVert); arrFree(&T->Color, &T->MaxColor); arrFree(&T->Normal, &T->MaxNormal); arrFree(&T->TexCoord, &T->MaxTexCoord); arrFree(&T->Index, &T->MaxIndex); arrFree(&T->DrawingCommand, &T->DrawingCommand); glDeleteBuffers(1, &T->VertBufObject); glDeleteBuffers(1, &T->ColorBufObject); glDeleteBuffers(1, &T->NormalBufObject); glDeleteBuffers(1, &T->TexCoordBufObject); glDeleteBuffers(1, &T->IndexBufObject); glBindVertexArray(0); glDeleteVertexArrays(1,&T->GlobalVAO); FreeMem(T->stack.level); memFree(T); } tnsMatrixStackItem *tKnlGetCurrentMatStackItem(){ return &T->stack.level[T->stack.current_level]; } tnsShader *tKnlGetActiveShader(){ return T->CurrentShader; } real *tnsGetModelMatrix(){ return tKnlGetCurrentMatStackItem()->model; } real *tnsGetViewMatrix(){ return tKnlGetCurrentMatStackItem()->view; } real *tnsGetProjectionMatrix(){ return tKnlGetCurrentMatStackItem()->projection; } void tnsGetMVMatrix(tnsMatrix44d r){ tnsMatrixStackItem *tmsi=tKnlGetCurrentMatStackItem(); tnsMatrix44d tmp; tnsMultiply44d(r, tmsi->model, tmsi->view); } void tnsGetMVPMatrix(tnsMatrix44d r){ tnsMatrixStackItem *tmsi=tKnlGetCurrentMatStackItem(); tnsMatrix44d tmp; tnsMultiply44d(tmp, tmsi->model, tmsi->view); tnsMultiply44d(r, tmp, tmsi->projection); } void tnsResetModelMatrix(){ tnsLoadIdentity44d(tnsGetModelMatrix()); } void tnsResetViewMatrix(){ tnsLoadIdentity44d(tnsGetViewMatrix()); } void tnsResetProjectionMatrix(){ tnsLoadIdentity44d(tnsGetProjectionMatrix()); } int tKnlAttatchShader(tnsShader *tns){ lstAppendItem(&T->Shaders, tns); tns->CustomID = T->NextShaderIndex; T->NextShaderIndex++; return tns->CustomID; }; int CMP_NUM_IsThisShader(tnsShader *tns, int *index){ return (tns->CustomID == *index); } tnsShader *tKnlFindShader1i(int CustomIndex){ return lstFindItem(&CustomIndex, CMP_NUM_IsThisShader, &T->Shaders); } void tKnlPushMatrix(){ tnsMatrixStack *tms = &T->stack; tnsShader *current_shader = tKnlGetActiveShader(); if (tms->current_level == tms->max_level || !current_shader) return; memcpy(&tms->level[tms->current_level + 1], &tms->level[tms->current_level], sizeof(tnsMatrixStackItem)); tms->current_level++; //tnsShaderApplyModel(current_shader,tms->level[tms->current_level].model); //tnsShaderApplyView(current_shader,tms->level[tms->current_level].view); //tnsShaderApplyProjection(current_shader,tms->level[tms->current_level].projection); }; void tKnlPopMatrix(){ tnsMatrixStack *tms = &T->stack; tnsShader *current_shader = tKnlGetActiveShader(); if (tms->current_level == 0 || !current_shader) return; tms->current_level--; tnsShaderApplyModel(current_shader, tms->level[tms->current_level].model); tnsShaderApplyView(current_shader, tms->level[tms->current_level].view); tnsShaderApplyProjection(current_shader, tms->level[tms->current_level].projection); } laListHandle *tKnlGetTextureList(){ return &T->Textures; } tnsBatch *tnsCreateBatch(u32bit NumVert, int Dimension, float *Data, int NormalDimension, float *Normal, int ColorDimension, float *Colors){ tnsBatch *b = CreateNew(tnsBatch); b->Dimension = Dimension; b->NormalDimension=NormalDimension; b->ColorDimension=ColorDimension; b->NumVert = NumVert; glGenBuffers(1, &b->VBO); glBindBuffer(GL_ARRAY_BUFFER, b->VBO); glBufferData(GL_ARRAY_BUFFER, NumVert * Dimension * sizeof(GLfloat), Data, GL_DYNAMIC_DRAW); if (Normal){ glGenBuffers(1, &b->NBO); glBindBuffer(GL_ARRAY_BUFFER, b->NBO); glBufferData(GL_ARRAY_BUFFER, NumVert * NormalDimension * sizeof(GLfloat), Normal, GL_DYNAMIC_DRAW); b->HasNormal=1; } if (Colors){ glGenBuffers(1, &b->CBO); glBindBuffer(GL_ARRAY_BUFFER, b->CBO); glBufferData(GL_ARRAY_BUFFER, NumVert * ColorDimension * sizeof(GLfloat), Colors, GL_DYNAMIC_DRAW); b->HasColor=1; } return b; } tnsBatch *tnsCreateBatchi(u32bit NumVert, int Dimension, int *Data){ tnsBatch *b = CreateNew(tnsBatch); b->Dimension = Dimension; b->NumVert = NumVert; glGenBuffers(1, &b->VBO); glBindBuffer(GL_ARRAY_BUFFER, b->VBO); glBufferData(GL_ARRAY_BUFFER, NumVert * Dimension * sizeof(GLuint), Data, GL_DYNAMIC_DRAW); return b; } void tnsCommandUseUniformColor(tnsBatchCommand*c, real* color){ tnsVectorCopy4d(color, c->UniformColor); c->UseUniformColor=1; } void tnsCommandOverrideColorArray(tnsBatchCommand*c, int VertCount, int ColorDimension, float* colors){ if(!colors) return; c->OverrideColorArray=1; glGenBuffers(1, &c->CBO); glBindBuffer(GL_ARRAY_BUFFER, c->CBO); glBufferData(GL_ARRAY_BUFFER, VertCount* ColorDimension * sizeof(GLfloat), colors, GL_DYNAMIC_DRAW); c->ColorDimension = ColorDimension; } tnsBatchCommand *tnsCreateCommand(tnsBatch *b, const char* name, u32bit ElementCount, int Dimension, GLenum DrawAs, u32bit *Elements, int HiddenByDefault){ tnsBatchCommand *bc = CreateNew(tnsBatchCommand); bc->ElementCount = ElementCount; bc->DrawAs = DrawAs; bc->Dimension = Dimension; bc->name=name; bc->HiddenByDefault = HiddenByDefault; if(Elements){ glGenBuffers(1, &bc->EBO); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, bc->EBO); glBufferData(GL_ELEMENT_ARRAY_BUFFER, ElementCount * Dimension * sizeof(GLuint), Elements, GL_DYNAMIC_DRAW); bc->DrawElements=1; }else{ bc->EBO=-1; } //int a = GetLastError(); lstAppendItem(&b->Branches, bc); return bc; } void tnsDeleteBatch(tnsBatch *b){ tnsBatchCommand *bc, *NextBc; glDeleteBuffers(1, &b->VBO); if (b->NBO > -1) glDeleteBuffers(1, &b->NBO); if (b->CBO > -1) glDeleteBuffers(1, &b->CBO); for (bc = b->Branches.pFirst; bc; bc = NextBc){ NextBc = bc->Item.pNext; lstRemoveItem(&b->Branches, bc); if (bc->EBO > -1) glDeleteBuffers(1, &bc->EBO); if (bc->CBO > -1) glDeleteBuffers(1, &bc->CBO); FreeMem(bc); } FreeMem(b); } void tnsDrawBatch(tnsBatch* batch, const char* OverrideCommand, real* OverrideUniformColor, int OverrideAsArray) { //int Mode = batch->DrawMode; if (!batch) return; tnsShader* cs=T->BindedShader; //glPolygonMode(GL_FRONT_AND_BACK,GL_LINE); glBindBuffer(GL_ARRAY_BUFFER, batch->VBO); glEnableVertexAttribArray(cs->iVertex); glVertexAttribPointer(cs->iVertex, batch->Dimension, GL_FLOAT, 0, 0, 0); if(cs->iNormal>=0){ if(batch->HasNormal){ glBindBuffer(GL_ARRAY_BUFFER, batch->NBO); glEnableVertexAttribArray(cs->iNormal); glVertexAttribPointer(cs->iNormal, batch->NormalDimension, GL_FLOAT, 0, 0, 0); tnsUniformUseNormal(cs,T->SetUseNormal); }else{ glDisableVertexAttribArray(cs->iNormal); glVertexAttrib3f(cs->iNormal,0,0,1); tnsUniformUseNormal(cs,0); } } if(cs->iColor>=0){ if(batch->HasColor){ glBindBuffer(GL_ARRAY_BUFFER, batch->CBO); glEnableVertexAttribArray(cs->iColor); glVertexAttribPointer(cs->iColor, batch->ColorDimension, GL_FLOAT, 0, 0, 0); } } int IsOverrideColor=0; for (tnsBatchCommand* bc = batch->Branches.pFirst; bc; bc = bc->Item.pNext) { if(OverrideCommand && !strSame(OverrideCommand, bc->name)){ continue; } if(!OverrideCommand && bc->HiddenByDefault){ continue; } if(cs->iColor){ if(bc->OverrideColorArray){ glBindBuffer(GL_ARRAY_BUFFER, bc->CBO); glEnableVertexAttribArray(cs->iColor); glVertexAttribPointer(cs->iColor, bc->ColorDimension, GL_FLOAT, 0, 0, 0); IsOverrideColor=1; }else{ if(batch->HasColor){ if(IsOverrideColor){ glBindBuffer(GL_ARRAY_BUFFER, batch->CBO); glEnableVertexAttribArray(cs->iColor); glVertexAttribPointer(cs->iColor, batch->ColorDimension, GL_FLOAT, 0, 0, 0); } }else{ glDisableVertexAttribArray(cs->iColor); glVertexAttrib4fv(cs->iColor,T->StateColor); } } if(bc->UseUniformColor || OverrideUniformColor){ glDisableVertexAttribArray(cs->iColor); IsOverrideColor=1; if(OverrideUniformColor){ glVertexAttrib4f(cs->iColor,LA_COLOR4(OverrideUniformColor)); } else glVertexAttrib4f(cs->iColor,LA_COLOR4(bc->UniformColor)); } } int DrawElements=OverrideAsArray?0:bc->DrawElements; if(DrawElements){ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, bc->EBO); glDrawElements(bc->DrawAs, bc->ElementCount*bc->Dimension, GL_UNSIGNED_INT, 0); }else{ glDrawArrays(bc->DrawAs,0,bc->ElementCount); } } //glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); } //==========================*=======================[Texture] int tnsGetTextureMemoryComponetCount(tnsTexture *t){ int Comp = 0; int CompSize; switch (t->GLTexBitsType){ case GL_RGB: Comp = 3; break; case GL_RGBA: Comp = 4; break; } return t->Width * t->Height * Comp; } int tnsInit2DTexture(tnsTexture *t, GLint glInternalFormat, int w, int h, int Multisample){ if (!t) return 0; if(0/*glInternalFormat==GL_DEPTH_COMPONENT32F*/){ t->Width = w; t->Height = h; t->GLTexBitsType = GL_DEPTH_COMPONENT32F; t->GLTexType = GL_RENDERBUFFER; t->Multisample = Multisample; glGenRenderbuffers(1, &t->GLTexHandle); tnsConfigure2DTexture(t); }else{ t->Width = w; t->Height = h; t->GLTexBitsType = glInternalFormat; t->GLTexType = Multisample?GL_TEXTURE_2D_MULTISAMPLE:GL_TEXTURE_2D; t->Multisample = Multisample; glGenTextures(1, &t->GLTexHandle); tnsConfigure2DTexture(t); } return 1; } int tnsInit3DTexture(tnsTexture *t, GLint glInternalFormat, int w, int h, int slices){ if (!t) return 0; t->Width = w; t->Height = h; t->GLTexBitsType = glInternalFormat; t->GLTexType = GL_TEXTURE_3D; glGenTextures(1, &t->GLTexHandle); tnsConfigure3DTexture(t); return 1; } void tnsConfigure2DTexture(tnsTexture *t){ tnsBindTexture(t); if(t->GLTexType==GL_RENDERBUFFER){ if(t->Multisample){ glRenderbufferStorageMultisample(GL_RENDERBUFFER, t->Multisample, t->GLTexBitsType, t->Width, t->Height); } else { glRenderbufferStorage(GL_RENDERBUFFER, t->GLTexBitsType, t->Width, t->Height); } }else{ int isDepth=t->GLTexBitsType==GL_DEPTH_COMPONENT||t->GLTexBitsType==GL_DEPTH_COMPONENT16|| t->GLTexBitsType==GL_DEPTH_COMPONENT24||t->GLTexBitsType==GL_DEPTH_COMPONENT32F; int format=isDepth?GL_DEPTH_COMPONENT:GL_RGBA; if(t->Multisample) glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, t->Multisample, t->GLTexBitsType, t->Width, t->Height, GL_TRUE); else{ glTexImage2D(GL_TEXTURE_2D, 0, t->GLTexBitsType, t->Width, t->Height, 0, format, GL_UNSIGNED_BYTE, 0); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); //glTexEnvi(GL_TEXTURE_2D, GL_TEXTURE_ENV_MODE, GL_REPLACE); } } tnsUnbindTexture(t); } void tnsConfigure3DTexture(tnsTexture *t){ tnsBindTexture(t); glTexImage3D(GL_TEXTURE_3D, 0, t->GLTexBitsType, t->Width, t->Height, t->Slices, 0, GL_RGBA, GL_FLOAT, 0); glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP); glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP); glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP); glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); //glTexEnvi(GL_TEXTURE_2D, GL_TEXTURE_ENV_MODE, GL_REPLACE); tnsUnbindTexture(t); } void tnsReconfigureTextureParameters(int Multisample){ laListHandle* l = tKnlGetTextureList(); for(tnsOffscreen* o=T->Offscreens.pFirst;o;o=o->Item.pNext){ tnsTexture* t=o->pColor[0]; if(t){ t->Multisample = Multisample; int recreate=0; if(t->Multisample){ if(t->GLTexType==GL_TEXTURE_2D){t->GLTexType=GL_TEXTURE_2D_MULTISAMPLE; recreate=1;}} else { if(t->GLTexType==GL_TEXTURE_2D_MULTISAMPLE){t->GLTexType=GL_TEXTURE_2D; recreate=1;}} if(recreate){ glDeleteTextures(1, &t->GLTexHandle); glGenTextures(1, &t->GLTexHandle); T->TexColor=0; } tnsConfigure2DTexture(t); tnsAttach2DOffscreenBuffer(o, GL_COLOR_ATTACHMENT0, t); } t=o->pDepth; if(t){ t->Multisample = Multisample; tnsConfigure2DTexture(t); tnsAttach2DOffscreenBuffer(o, GL_DEPTH_ATTACHMENT, t); } } } tnsTexture *tnsCreate2DTexture(GLint glInternalFormat, int w, int h, int Multisample){ tnsTexture *tex = memAcquire(sizeof(tnsTexture)); tnsInit2DTexture(tex, glInternalFormat, w, h, Multisample); laNotifyUsers("tns.texture_list"); lstAppendItem(tKnlGetTextureList(), tex); return tex; }; tnsTexture *tnsCreate3DTexture(GLint glInternalFormat, int w, int h, int slices){ tnsTexture *tex = memAcquire(sizeof(tnsTexture)); tnsInit3DTexture(tex, glInternalFormat, w, h, slices); laNotifyUsers("tns.texture_list"); lstAppendItem(tKnlGetTextureList(), tex); return tex; }; void tnsCopyScreenTo2DTexture(tnsTexture *target, int x_lower_left, int y_lower_left, int w, int h){ if(target->GLTexType!=GL_TEXTURE_2D) return; tnsBindTexture(target); glReadBuffer(GL_BACK); glCopyTexSubImage2D(target->GLTexType, 0, 0, 0, x_lower_left, y_lower_left, w, h); tnsUnbindTexture(); } void tnsUseMaskTexture(tnsTexture *t){ if(!t){T->StateTextureMode=0; return;} T->StateTexColor = t; T->StateTextureMode=1; } void tnsUseTexture(tnsTexture *t){ if(!t){T->StateTextureMode=0; return;} if(t->GLTexType == GL_TEXTURE_2D){ T->StateTexColor = t; T->StateTextureMode=2; } else if(t->GLTexType == GL_TEXTURE_2D_MULTISAMPLE){ T->StateTexColor = t; T->StateTextureMode=3; } } void tnsUseNoTexture(){ tnsUseTexture(0); } void tnsUseMultiplyColor(int enable){ T->StateMultiplyColor=enable?1:0; } void tnsUniformUseNormal(tnsShader* s, int Use){ if(T->StateUseNormal!=Use){ T->StateUseNormal=Use; glUniform1i(s->iUseNormal,Use); } } void tnsUseNormal(int Use){ T->SetUseNormal=Use; } void tnsActiveTexture(GLenum tex){ if (T->GlTextureSets != tex) glActiveTexture(tex); T->GlTextureSets = tex; } void tnsBindTexture(tnsTexture *t){ if (!t || T->TexColor==t) return; if(t->GLTexType == GL_TEXTURE_2D){ tnsActiveTexture(GL_TEXTURE0); glBindTexture(t->GLTexType, t->GLTexHandle); T->TexColor=t;} elif(t->GLTexType == GL_TEXTURE_2D_MULTISAMPLE){ tnsActiveTexture(GL_TEXTURE1); glBindTexture(t->GLTexType, t->GLTexHandle); T->TexColor=t;} elif(t->GLTexType == GL_RENDERBUFFER){ glBindRenderbufferEXT(GL_RENDERBUFFER, t->GLTexHandle); T->TexRenderbuffer = t;} elif(t->GLTexType == GL_TEXTURE_3D){ tnsActiveTexture(GL_TEXTURE0); glBindTexture(t->GLTexType, t->GLTexHandle); T->TexColor=t;} } void tnsUnbindTexture(){ if(T->TexRenderbuffer){ if(T->TexRenderbuffer->GLTexType == GL_RENDERBUFFER){ glBindRenderbufferEXT(GL_RENDERBUFFER, 0); T->TexRenderbuffer=0;}} if(T->TexColor){ if(T->TexColor->GLTexType == GL_TEXTURE_2D){tnsActiveTexture(GL_TEXTURE0);} else if(T->TexColor->GLTexType == GL_TEXTURE_2D_MULTISAMPLE){tnsActiveTexture(GL_TEXTURE1);} else if(T->TexColor->GLTexType == GL_TEXTURE_3D){tnsActiveTexture(GL_TEXTURE0);} glBindTexture(T->TexColor->GLTexType, -1); T->TexColor=0; } } void tnsUniformUseTexture(tnsShader* s, int mode, int sample){ if(s->StateTextureMode != mode){ s->StateTextureMode=mode; glUniform1i(s->iTextureMode,mode); } if(mode==3 && s->StateSampleAmount != sample){ s->StateSampleAmount=sample, glUniform1i(s->iSampleAmount,sample); } } void tnsUniformUseMultiplyColor(tnsShader* s, int enable){ int mode=enable?1:0; if(s->StateMultiplyColor != mode){ s->StateMultiplyColor=mode; glUniform1i(s->iMultiplyColor,mode); } } void tnsUniformColorMode(tnsShader* s, int mode){ glUniform1i(s->iColorMode,mode); } void tnsUniformInputColorSpace(tnsShader* s, int ColorSpace){ glUniform1i(s->iInputColorSpace,ColorSpace); } void tnsUniformOutputColorSpace(tnsShader* s, int ColorSpace){ glUniform1i(s->iOutputColorSpace,ColorSpace); } void tnsUniformShowColorOverflowStripes(tnsShader* s, int Show){ glUniform1i(s->iShowStripes,Show); } void tnsDraw2DTextureDirectly(tnsTexture *t, real x, real y, real w, real h){ real Verts[8]; real UV[8] = { 0.0f, 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f}; tnsMakeQuad2d(Verts, x, y, x + w, y, x + w, y + h, x, y + h); tnsUseTexture(t); tnsVertexArray2d(Verts, 4); tnsTexCoordArray2d(UV, 4); tnsPackAs(GL_TRIANGLE_FAN); } void tnsDraw2DTextureArg(tnsTexture *t, real x_upper_right, real y_upper_right, int w, int h, real *MultiplyColor, real LPadding, real RPadding, real TPadding, real BPadding){ real Verts[8]; real UV[8] = { 0.0f + LPadding, 1.0f - TPadding, 1.0f - RPadding, 1.0f - TPadding, 1.0f - RPadding, 0.0f + BPadding, 0.0f + LPadding, 0.0f + BPadding}; tnsMakeQuad2d(Verts, x_upper_right, y_upper_right, x_upper_right + w, y_upper_right, x_upper_right + w, y_upper_right + h, x_upper_right, y_upper_right + h); if (MultiplyColor){ tnsColor4dv(MultiplyColor); tnsUseMultiplyColor(1); } tnsUseTexture(t); tnsVertexArray2d(Verts, 4); tnsTexCoordArray2d(UV, 4); tnsPackAs(GL_TRIANGLE_FAN); tnsUseMultiplyColor(0); } void tnsDeleteTexture(tnsTexture *t){ laListHandle *lst = tKnlGetTextureList(); tnsUnbindTexture(); if (!t) return; if (t->GLTexType == GL_RENDERBUFFER){ glBindRenderbufferEXT(GL_RENDERBUFFER, t->GLTexHandle); glDeleteRenderbuffersEXT(1, &t->GLTexHandle); }else{ //glBindTexture(t->GLTexType, 0); glDeleteTextures(1, &t->GLTexHandle); } laNotifyUsers("tns.texture_list"); lstRemoveItem(lst, t); if (t->DrawData) FreeMem(t->DrawData); memFree(t); } int tnsTextureMemorySize(tnsTexture *t, int Mem){ int ElemSize; if (Mem) return t->Width * t->Height * sizeof(void *); switch (t->GLTexBitsType){ default: case GL_RED: ElemSize = sizeof(char) * 1; break; case GL_RG: ElemSize = sizeof(char) * 2; break; case GL_RGB: ElemSize = sizeof(char) * 3; break; case GL_RGBA: ElemSize = sizeof(char) * 4; break; case GL_RGBA32F: ElemSize = sizeof(float) * 4; break; case GL_DEPTH_COMPONENT32F: ElemSize = sizeof(float); break; } t->ElemSize = ElemSize; return t->Width * t->Height * ElemSize; } void tnsCreateTextureReadbackBuffer(tnsTexture *t){ if (t->SamplePtr){ tnsTextureSample *tns; memset(t->SamplePtr, 0, tnsTextureMemorySize(t, 1)); while (tns = lstPopItem(&t->ErasedSamples)) FreeMem(tns); while (tns = lstPopItem(&t->PendingSamples)) FreeMem(tns); }else{ t->TextureReadBack = calloc(1, tnsTextureMemorySize(t, 0)); t->SamplePtr = calloc(1, tnsTextureMemorySize(t, 1)); } t->RBWidth = t->Width; t->RBHeight = t->Height; } void tnsDeleteTextureReadbackBuffer(tnsTexture *t){ FreeMem(t->TextureReadBack); FreeMem(t->SamplePtr); tnsTextureSample *tns; while (tns = lstPopItem(&t->ErasedSamples)) FreeMem(tns); while (tns = lstPopItem(&t->PendingSamples)) FreeMem(tns); t->RBWidth = t->RBHeight = 0; } void tnsReadbackTexture(tnsTexture *t){ //if (t->RBWidth != t->Width || t->RBHeight != t->Height) tnsDeleteTextureReadbackBuffer(t); // //tnsCreateTextureReadbackBuffer(t); // //tnsBindTexture(t); //glGetTexImage(t->GLTexType, 0, t->DataFormat, t->DataType, t->TextureReadBack); //tnsUnbindTexture(); // //int w, h; //tnsTextureSample *tns; //u8bit sample; //for (h = 0; h < t->Height; h++){ // for (w = 0; w < t->Width; w++){ // int index = h * t->Width + w; // if ((sample = *tnsTextureSampleU8(t, w, h)) > TNS_SNAKE_STRENGTH_LIMIT){ // tns = CreateNew(tnsTextureSample); // lstAppendItem(&t->PendingSamples, tns); // t->SamplePtr[h * t->Width + w] = tns; // tns->X = w; // tns->Y = h; // tns->Sample = sample; // } // } //} } //====================================================[NEW RENDER KERNEL] //=================[Immediate-style api] void tnsColor4d(real r, real g, real b, real a){ T->StateColor[0] = r; T->StateColor[1] = g; T->StateColor[2] = b; T->StateColor[3] = a; } void tnsColor4dv(real *rgba){ T->StateColor[0] = rgba[0]; T->StateColor[1] = rgba[1]; T->StateColor[2] = rgba[2]; T->StateColor[3] = rgba[3]; } void tnsPolygonMode(GLenum PolyMode){ T->StatePolyMode = PolyMode; } void tnsShadeMode(GLenum ShadeMode){ T->StateShadeMode = ShadeMode; } void tnsVertex3d(real x, real y, real z){ tnsCommand *c = &T->DrawingCommand[T->NextCommand]; int vend = c->VertEnd; c->UseVert = 1; if (!c->Dimensions) c->Dimensions = 3; if(arrEnsureLength(&T->Vert, T->NextVert+c->Dimensions, &T->MaxVert, sizeof(GLfloat))){ glBindBuffer(GL_ARRAY_BUFFER, T->VertBufObject); glBufferData(GL_ARRAY_BUFFER, T->MaxVert * sizeof(GLfloat), 0, GL_DYNAMIC_DRAW); } GLfloat *varr = T->Vert; if (c->Dimensions == 3){ varr[vend] = x; varr[vend + 1] = y; varr[vend + 2] = z; c->NumVert++; T->NextVert += 3; c->VertEnd += 3; }else{ varr[vend] = x; varr[vend + 1] = y; c->NumVert++; T->NextVert += 2; c->VertEnd += 2; } } void tnsVertex2d(real x, real y){ tnsCommand *c = &T->DrawingCommand[T->NextCommand]; int vend = c->VertEnd; c->UseVert = 1; if (!c->Dimensions) c->Dimensions = 2; if(arrEnsureLength(&T->Vert, T->NextVert+c->Dimensions, &T->MaxVert, sizeof(GLfloat))){ glBindBuffer(GL_ARRAY_BUFFER, T->VertBufObject); glBufferData(GL_ARRAY_BUFFER, T->MaxVert * sizeof(GLfloat), 0, GL_DYNAMIC_DRAW); } GLfloat *varr = T->Vert; if (c->Dimensions == 2){ varr[vend] = x; varr[vend + 1] = y; c->NumVert++; T->NextVert += 2; c->VertEnd += 2; }else{ tnsVertex3d(x, y, 0.0f); } } void tnsVertexArray2d(real *verts, int amount){ tnsCommand *c = &T->DrawingCommand[T->NextCommand]; int trans = 2 * amount; int vend = c->VertEnd; c->UseVert = 1; if (!c->Dimensions) c->Dimensions = 2; if(arrEnsureLength(&T->Vert, T->NextVert+c->Dimensions*amount, &T->MaxVert, sizeof(GLfloat))){ glBindBuffer(GL_ARRAY_BUFFER, T->VertBufObject); glBufferData(GL_ARRAY_BUFFER, T->MaxVert * sizeof(GLfloat), 0, GL_DYNAMIC_DRAW); } GLfloat *varr = T->Vert; if (c->Dimensions == 2){ int i; for (i = 0; i < trans; i++){ varr[vend] = verts[i]; vend++; } //memcpy(&varr[vend], verts, trans*sizeof(real)); c->VertEnd += trans; c->NumVert += amount; T->NextVert += trans; } } void tnsVertexArray3d(real *verts, int amount){ tnsCommand *c = &T->DrawingCommand[T->NextCommand]; int trans = 3 * amount; int vend = c->VertEnd; c->UseVert = 1; if (!c->Dimensions) c->Dimensions = 3; if(arrEnsureLength(&T->Vert, T->NextVert+c->Dimensions*amount, &T->MaxVert, sizeof(GLfloat))){ glBindBuffer(GL_ARRAY_BUFFER, T->VertBufObject); glBufferData(GL_ARRAY_BUFFER, T->MaxVert * sizeof(GLfloat), 0, GL_DYNAMIC_DRAW); } GLfloat *varr = T->Vert; if (c->Dimensions == 3){ int i; for (i = 0; i < trans; i++){ varr[vend] = verts[i]; vend++; } //memcpy(&varr[vend], verts, trans*sizeof(real)); c->VertEnd += trans; c->NumVert += amount; T->NextVert += trans; } } void tnsColorArray4d(real *colors, int amount){ tnsCommand *c = &T->DrawingCommand[T->NextCommand]; int trans = 4 * amount; int ofst = c->ColorEnd; c->UseColor = 1; if(arrEnsureLength(&T->Color, T->NextColor+4*amount, &T->MaxColor, sizeof(GLfloat))){ glBindBuffer(GL_ARRAY_BUFFER, T->ColorBufObject); glBufferData(GL_ARRAY_BUFFER, T->MaxColor * sizeof(GLfloat), 0, GL_DYNAMIC_DRAW); } GLfloat *carr = T->Color; int i; for (i = 0; i < trans; i++){ carr[ofst] = colors[i]; ofst++; } //memcpy(&T->Color[c->ColorEnd], colors, trans*sizeof(real)); c->ColorEnd += trans; T->NextColor += trans; } void tnsNormalArray3d(real *normals, int amount){ tnsCommand *c = &T->DrawingCommand[T->NextCommand]; int trans = 3 * amount; int ofst = c->NormalEnd; c->UseNormal = 1; if(arrEnsureLength(&T->Normal, T->NextNormal+3*amount, &T->MaxNormal, sizeof(GLfloat))){ glBindBuffer(GL_ARRAY_BUFFER, T->NormalBufObject); glBufferData(GL_ARRAY_BUFFER, T->MaxNormal * sizeof(GLfloat), 0, GL_DYNAMIC_DRAW); } GLfloat *narr = T->Normal; int i; for (i = 0; i < trans; i++){ narr[ofst] = normals[i]; ofst++; } //memcpy(&T->Normal[c->NormalEnd], normals, trans*sizeof(real)); c->NormalEnd += trans; T->NextNormal += trans; } void tnsTexCoordArray2d(real *coords, int amount){ tnsCommand *c = &T->DrawingCommand[T->NextCommand]; int trans = 2 * amount; int ofst = c->TexCoordEnd; c->UseTexCoord = 1; c->UVDimensions = 2; if(arrEnsureLength(&T->TexCoord, T->NextTexCoord+2*amount, &T->MaxTexCoord, sizeof(GLfloat))){ glBindBuffer(GL_ARRAY_BUFFER, T->TexCoordBufObject); glBufferData(GL_ARRAY_BUFFER, T->MaxTexCoord * sizeof(GLfloat), 0, GL_DYNAMIC_DRAW); } GLfloat *carr = T->TexCoord; int i; for (i = 0; i < trans; i++){ carr[ofst] = coords[i]; ofst++; } //memcpy(&T->TexCoord[c->TexCoordEnd], coords, trans*sizeof(real)); c->TexCoordEnd += trans; T->NextTexCoord += trans; } void tnsTexCoordArray3d(real *coords, int amount){ tnsCommand *c = &T->DrawingCommand[T->NextCommand]; int trans = 3 * amount; int ofst = c->TexCoordEnd; c->UseTexCoord = 1; c->UVDimensions = 3; if(arrEnsureLength(&T->TexCoord, T->NextTexCoord+3*amount, &T->MaxTexCoord, sizeof(GLfloat))){ glBindBuffer(GL_ARRAY_BUFFER, T->TexCoordBufObject); glBufferData(GL_ARRAY_BUFFER, T->MaxTexCoord * sizeof(GLfloat), 0, GL_DYNAMIC_DRAW); } GLfloat *carr = T->TexCoord; int i; for (i = 0; i < trans; i++){ carr[ofst] = coords[i]; ofst++; } c->TexCoordEnd += trans; T->NextTexCoord += trans; } void tnsIndexArray(GLuint *index, short amount){ tnsCommand *c = &T->DrawingCommand[T->NextCommand]; //if (c->UseIndex) return; c->UseIndex = 1; if(arrEnsureLength(&T->Index, T->NextIndex+amount, &T->MaxIndex, sizeof(GLuint))){ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, T->IndexBufObject); glBufferData(GL_ELEMENT_ARRAY_BUFFER, T->MaxIndex * sizeof(GLuint), 0, GL_DYNAMIC_DRAW); } memcpy(&T->Index[c->IndexEnd], index, amount * sizeof(GLuint)); c->IndexEnd += amount; c->NumIndex += amount; T->NextIndex += amount; } void tnsPackAs(GLenum Mode){ arrEnsureLength(&T->DrawingCommand, T->NextCommand+1, &T->MaxCommand, sizeof(tnsCommand)); tnsCommand *c = &T->DrawingCommand[T->NextCommand]; tnsCommand *nc; T->NextCommand++; nc = &T->DrawingCommand[T->NextCommand]; memcpy(c->UniformColor, T->StateColor, sizeof(GLfloat) * 4); if (Mode == GL_QUAD_STRIP || Mode == GL_QUADS) Mode=GL_TRIANGLE_STRIP; //if (Mode == GL_QUADS) Mode=GL_TRIANGLE_STRIP; c->Mode = Mode; c->ReplaceShader = T->StateShader; c->PolyMode = T->StatePolyMode; c->Shade = T->StateShadeMode; c->ColorTexture = T->StateTexColor; c->TextureMode = T->StateTextureMode; c->MultiplyColor = T->StateMultiplyColor; memset(nc, 0, sizeof(tnsCommand)); nc->VertBegin = nc->VertEnd = c->VertEnd; nc->NormalBegin = nc->NormalEnd = c->NormalEnd; nc->ColorBegin = nc->ColorEnd = c->ColorEnd; nc->TexCoordBegin = nc->TexCoordEnd = c->TexCoordEnd; nc->IndexBegin = nc->IndexEnd = c->IndexEnd; } void tnsFlush(){ tnsShader *cs = T->CurrentShader; tnsCommand *tc = &T->DrawingCommand[0]; tnsCommand *c = tc; int PrevDimensions = 0; int LastVertBegin = 0; if (!c || !cs) return; if (T->NextVert){ glBindBuffer(GL_ARRAY_BUFFER, T->VertBufObject); //glEnableVertexAttribArray(cs->iVertex); glBufferSubData(GL_ARRAY_BUFFER, 0, T->NextVert * sizeof(GLfloat), T->Vert); } if (T->NextColor){ glBindBuffer(GL_ARRAY_BUFFER, T->ColorBufObject); //glEnableVertexAttribArray(cs->iColor); glBufferSubData(GL_ARRAY_BUFFER, 0, T->NextColor * sizeof(GLfloat), T->Color); } if (T->NextNormal){ glBindBuffer(GL_ARRAY_BUFFER, T->NormalBufObject); //glEnableVertexAttribArray(cs->iColor); glBufferSubData(GL_ARRAY_BUFFER, 0, T->NextNormal * sizeof(GLfloat), T->Normal); } if (T->NextTexCoord){ glBindBuffer(GL_ARRAY_BUFFER, T->TexCoordBufObject); //glEnableVertexAttribArray(cs->iColor); glBufferSubData(GL_ARRAY_BUFFER, 0, T->NextTexCoord * sizeof(GLfloat), T->TexCoord); } for (int i=0;iNextCommand;i++){ c=&T->DrawingCommand[i]; if (c->PolyMode != T->StatePolyMode){glPolygonMode(GL_FRONT_AND_BACK, c->PolyMode); T->StatePolyMode=c->PolyMode;} if (c->Shade != T->StateShadeMode){glShadeModel(c->Shade); T->StateShadeMode=c->Shade;} if (c->ReplaceShader && c->ReplaceShader != T->CurrentShader){ tnsEnableShaderv(c->ReplaceShader); cs = c->ReplaceShader; if (!cs) continue; } glBindBuffer(GL_ARRAY_BUFFER, T->VertBufObject); if (c->UseVert){ glEnableVertexAttribArray(cs->iVertex); glVertexAttribPointer(cs->iVertex, (c->Dimensions ? c->Dimensions : PrevDimensions), GL_FLOAT, 0, 0, c->VertBegin * sizeof(GLfloat)); LastVertBegin = c->VertBegin; }else{ glEnableVertexAttribArray(cs->iVertex); glVertexAttribPointer(cs->iVertex, (c->Dimensions ? c->Dimensions : PrevDimensions), GL_FLOAT, 0, 0, LastVertBegin * sizeof(GLfloat)); } PrevDimensions = (c->Dimensions ? c->Dimensions : PrevDimensions); if (c->UseIndex){ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, T->IndexBufObject); glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, c->NumIndex * sizeof(GLuint), &T->Index[c->IndexBegin]); } if (cs->iNormal != -1){ glBindBuffer(GL_ARRAY_BUFFER, T->NormalBufObject); if (c->UseNormal){ glEnableVertexAttribArray(cs->iNormal); tnsUniformUseNormal(cs,1); } glVertexAttribPointer(cs->iNormal, 3, GL_FLOAT, 0, 0, c->NormalBegin * sizeof(GLfloat)); if (!c->UseNormal || c->Dimensions == 2){ glDisableVertexAttribArray(cs->iNormal); tnsUniformUseNormal(cs,0); glVertexAttrib3f(cs->iNormal, 0, 0, -1); } } if (cs->iColor != -1){ glBindBuffer(GL_ARRAY_BUFFER, T->ColorBufObject); if (c->UseColor){ glEnableVertexAttribArray(cs->iColor); glVertexAttribPointer(cs->iColor, 4, GL_FLOAT, 0, 0, c->ColorBegin * sizeof(GLfloat)); }else{ glDisableVertexAttribArray(cs->iColor); glVertexAttrib4fv(cs->iColor, c->UniformColor); } } if (cs->iUV != -1){ if (c->UseTexCoord){ glBindBuffer(GL_ARRAY_BUFFER, T->TexCoordBufObject); if (c->UseTexCoord){ glEnableVertexAttribArray(cs->iUV); glVertexAttribPointer(cs->iUV, c->UVDimensions, GL_FLOAT, 0, 0, c->TexCoordBegin * sizeof(GLfloat)); } else{ glDisableVertexAttribArray(cs->iUV); } } } if (c->TextureMode && c->ColorTexture && cs->iTexColor != -1){ tnsBindTexture(c->ColorTexture); tnsUniformUseTexture(cs, c->TextureMode, c->ColorTexture->Multisample); }else{ tnsUniformUseTexture(cs, 0, 0); //tnsUnbindTexture(); } if(cs->iMultiplyColor != -1){ tnsUniformUseMultiplyColor(cs, c->MultiplyColor); } if (c->UseIndex){ glDrawElements(c->Mode, c->NumIndex, GL_UNSIGNED_INT, 0); }else{ glDrawArrays(c->Mode, 0, c->NumVert); } } T->NextCommand=0; c = &T->DrawingCommand[0]; memset(c, 0, sizeof(tnsCommand)); c->ColorBegin = c->ColorEnd = T->NextColor = 0; c->NormalBegin = c->NormalEnd = T->NextNormal = 0; c->TexCoordBegin = c->TexCoordEnd = T->NextTexCoord = 0; c->VertBegin = c->VertEnd = T->NextVert = 0; c->IndexBegin = c->IndexEnd = T->NextIndex = 0; //must --why? //T->BindedShader = 0; }; //============================================================================================[offscr] const GLuint TNS_ATTACHMENT_ARRAY_NONE[] = {GL_NONE}; const GLuint TNS_ATTACHMENT_ARRAY[] = {GL_COLOR_ATTACHMENT0}; const GLuint TNS_ATTACHMENT_ARRAY_1[] = {GL_COLOR_ATTACHMENT1}; const GLuint TNS_ATTACHMENT_ARRAY_2[] = {GL_COLOR_ATTACHMENT2}; const GLuint TNS_ATTACHMENT_ARRAY_1_2[] = {GL_COLOR_ATTACHMENT1, GL_COLOR_ATTACHMENT2}; const GLuint TNS_ATTACHMENT_ARRAY_0_1_2[] = {GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1, GL_COLOR_ATTACHMENT2}; const GLenum TNS_WINDOW_DRAWBUFFER_ARRAY[] = {GL_BACK}; tnsOffscreen *tnsCreateOffscreenHandle(){ tnsOffscreen *toff = CreateNew(tnsOffscreen); glGenFramebuffers(1, &toff->FboHandle); lstAppendItem(&T->Offscreens, toff); return toff; } void tnsAttach2DOffscreenBuffer(tnsOffscreen *target, GLuint attatchment, tnsTexture *use){ if (!target || !use || target->FboHandle == -1 || use->GLTexHandle == -1) return; if (attatchment >= GL_COLOR_ATTACHMENT0 && attatchment <= GL_COLOR_ATTACHMENT15){ //if (target->pColor[attatchment - GL_COLOR_ATTACHMENT0]) return; glBindFramebuffer(GL_FRAMEBUFFER, target->FboHandle); tnsBindTexture(use); glFramebufferTexture2D(GL_FRAMEBUFFER, attatchment, use->GLTexType, use->GLTexHandle, 0); target->pColor[attatchment - GL_COLOR_ATTACHMENT0] = use; tnsUnbindTexture(); glBindFramebuffer(GL_FRAMEBUFFER, 0); }elif (attatchment == GL_DEPTH_ATTACHMENT){ //if (target->pDepth) return; glBindFramebuffer(GL_FRAMEBUFFER, target->FboHandle); tnsBindTexture(use); glFramebufferTexture2D(GL_FRAMEBUFFER, attatchment, use->GLTexType, use->GLTexHandle, 0); //glBindRenderbufferEXT(GL_RENDERBUFFER, use->GLTexHandle); //glBindFramebuffer(GL_FRAMEBUFFER, target->FboHandle); //glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, use->GLTexHandle); target->pDepth = use; tnsUnbindTexture(); glBindFramebuffer(GL_FRAMEBUFFER, 0); //glBindRenderbufferEXT(GL_RENDERBUFFER, 0); //glBindFramebuffer(GL_FRAMEBUFFER, 0); } GLenum result = glCheckFramebufferStatus(GL_FRAMEBUFFER); //if (result == GL_FRAMEBUFFER_COMPLETE) { // printf("Framebuffer complete!\n"); //} //else { // printf("Framebuffer incomplete!\n"); //} } void tnsDetach2DOffscreenBuffer(tnsOffscreen *target, GLuint which_attach_point){ if (which_attach_point >= GL_COLOR_ATTACHMENT0 && which_attach_point <= GL_COLOR_ATTACHMENT15){ if (target->pColor[which_attach_point - GL_COLOR_ATTACHMENT0] == 0) return; glBindFramebuffer(GL_FRAMEBUFFER, target->FboHandle); glFramebufferTexture2D(GL_FRAMEBUFFER, which_attach_point, GL_TEXTURE_2D, 0, 0); tnsDeleteTexture(target->pColor[which_attach_point - GL_COLOR_ATTACHMENT0]); target->pColor[which_attach_point - GL_COLOR_ATTACHMENT0] = 0; }elif (which_attach_point == GL_DEPTH_ATTACHMENT){ if (target->pDepth) return; glBindFramebuffer(GL_FRAMEBUFFER, target->FboHandle); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, 0, 0); tnsDeleteTexture(target->pDepth); target->pDepth = 0; } glBindFramebuffer(GL_FRAMEBUFFER, 0); tnsUnbindTexture(); } tnsOffscreen *tnsCreate2DOffscreen(int glInternalFormat, int w, int h, int Multisample, int WithDepth){ tnsOffscreen *toff = tnsCreateOffscreenHandle(); tnsTexture *color; tnsTexture *depth; if(glInternalFormat){ color = tnsCreate2DTexture(glInternalFormat, w, h, Multisample); tnsAttach2DOffscreenBuffer(toff, GL_COLOR_ATTACHMENT0, color); } if(WithDepth){ depth = tnsCreate2DTexture(GL_DEPTH_COMPONENT, w, h, Multisample); tnsAttach2DOffscreenBuffer(toff, GL_DEPTH_ATTACHMENT, depth); } return toff; } tnsOffscreen *tnsCreateDeferredOffscreen(int w, int h){ tnsOffscreen *toff = tnsCreateOffscreenHandle(); tnsTexture *color,*normal,*gpos; tnsTexture *depth; color = tnsCreate2DTexture(GL_RGBA8, w, h, 0); tnsAttach2DOffscreenBuffer(toff, GL_COLOR_ATTACHMENT0, color); normal = tnsCreate2DTexture(GL_RGB8, w, h, 0); tnsAttach2DOffscreenBuffer(toff, GL_COLOR_ATTACHMENT1, normal); gpos = tnsCreate2DTexture(GL_RGB32F, w, h, 0); tnsAttach2DOffscreenBuffer(toff, GL_COLOR_ATTACHMENT2, gpos); depth = tnsCreate2DTexture(GL_DEPTH_COMPONENT, w, h, 0); tnsAttach2DOffscreenBuffer(toff, GL_DEPTH_ATTACHMENT, depth); return toff; } void tnsConfigureOffscreen(tnsOffscreen *off, int w, int h){ tnsTexture* t=off->pColor[0]; t->Width = w; t->Height = h; tnsConfigure2DTexture(t); t=off->pDepth; if(t){ t->Width = w; t->Height = h; tnsConfigure2DTexture(t); } } void tnsDelete2DOffscreen(tnsOffscreen *o){ if (!o) return; glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); for(int i=0;i<16;i++){ if(o->pColor[i]){ tnsDetach2DOffscreenBuffer(o, GL_COLOR_ATTACHMENT0+i); tnsDeleteTexture(o->pColor[0]); } } if(o->pDepth){ tnsDetach2DOffscreenBuffer(o, GL_DEPTH_ATTACHMENT); tnsDeleteTexture(o->pDepth); } glDeleteFramebuffers(1, &o->FboHandle); //tnsDeleteTexture(o->pStencil); lstRemoveItem(&T->Offscreens, o); FreeMem(o); } void tnsDrawToOffscreen(tnsOffscreen *toff, int HowMany, GLuint *AttachmentArray){ if (!toff) return; glBindFramebuffer(GL_DRAW_FRAMEBUFFER, toff->FboHandle); if(AttachmentArray==TNS_ATTACHMENT_ARRAY_NONE){glDrawBuffer(GL_NONE);} else glDrawBuffers((HowMany ? HowMany : 1), (AttachmentArray ? AttachmentArray : TNS_ATTACHMENT_ARRAY)); T->IsOffscreen = 1; T->BindedShader = 0; } //void tnsDraw_toextraColorAttachment(tnsOffscreen *toff){ // if (!toff) return; // if (!toff->pColor[1]){ // tnsCreate2DOffscreenMSAttachmentExtraColor(toff); // } // glBindFramebuffer(GL_DRAW_FRAMEBUFFER, toff->FboHandle); // glDrawBuffers(1, TNS_ATTACHMENT_ARRAY_1); // T->IsOffscreen = 1; // T->BindedShader = 0; //} //void tnsDraw_toextraNormalAttachment(tnsOffscreen *toff){ // if (!toff) return; // if (!toff->pColor[2]){ // tnsCreate2DOffscreenMSAttachmentExtraNormal(toff); // } // glBindFramebuffer(GL_DRAW_FRAMEBUFFER, toff->FboHandle); // glDrawBuffers(1, TNS_ATTACHMENT_ARRAY_2); // T->IsOffscreen = 1; // T->BindedShader = 0; //} //void tnsDrawToAllExtraAttachments(tnsOffscreen *toff){ // if (!toff) return; // if (!toff->pColor[1]){ // tnsCreate2DOffscreenMSAttachmentExtraColor(toff); // } // if (!toff->pColor[2]){ // tnsCreate2DOffscreenMSAttachmentExtraNormal(toff); // } // glBindFramebuffer(GL_DRAW_FRAMEBUFFER, toff->FboHandle); // glDrawBuffers(2, TNS_ATTACHMENT_ARRAY_1_2); // T->IsOffscreen = 1; // T->BindedShader = 0; //} void tnsDrawToOffscreenOnlyBind(tnsOffscreen *toff, int HowMany, GLuint *AttachmentArray){ if (!toff) return; glBindFramebuffer(GL_DRAW_FRAMEBUFFER, toff->FboHandle); } void tnsReadFromOffscreen(tnsOffscreen *toff){ if (!toff) return; glBindFramebuffer(GL_READ_FRAMEBUFFER, toff->FboHandle); } void tnsPassColorBetweenOffscreens(tnsOffscreen *from, tnsOffscreen *to, GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLenum FilterMode){ if (!from || !to) return; glBlitFramebufferEXT( srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, GL_COLOR_BUFFER_BIT, FilterMode); } void tnsDrawToScreen(){ glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); glDrawBuffer(GL_BACK); T->IsOffscreen = 0; T->BindedShader = 0; } //===========================================================================[FONT] tnsFontManager *FM; void tnsSetuptnsFontManager(){ FM = CreateNew(tnsFontManager); }; void tnsQuitFontManager(){ tnsInvalidateFontCache(); tnsFont*f=FM->UsingFont; for(int i=0;iNumFaces;i++){ FT_Done_Face(f->ftface[i]); } if(f->ftfacemono) FT_Done_Face(f->ftfacemono); FT_Done_FreeType(f->ftlib); free(f->characters); free(f->monocharacters); free(f); FreeMem(FM); } int next_p2(int a){ int rval = 1; while (rval < a) rval <<= 1; return rval; } int tnsGetMonoFontAdvance(){ return FM->UsingFont->MonoAdvance; } int tnsInvalidateFontCache(){ tnsFont*f=FM->UsingFont; for(int i=0;icharacters[i]){ free(f->characters[i]); f->characters[i]=0; } } for(int i=0;imonocharacters[i]){ free(f->monocharacters[i]); f->monocharacters[i]=0; } } f->CurrentX=f->CurrentY=0; f->height = LA_RH*(MAIN.FontSize/2.0f+0.5f); int GenHeight=LA_RH*MAIN.FontSize; for(int i=0;iNumFaces;i++){ FT_Set_Char_Size(f->ftface[i], 0, GenHeight << 6, 96, 96); } if(f->ftfacemono){ FT_Set_Char_Size(f->ftfacemono, 0, (GenHeight << 6)*f->MonoScale, 96, 96); FT_Glyph glyph; if (FT_Load_Char(f->ftfacemono, 'a', FT_LOAD_TARGET_NORMAL | FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP)|| FT_Get_Glyph(f->ftfacemono->glyph, &glyph)){ SEND_PANIC_ERROR("Monospace font doesn't contain character 'a'"); } f->MonoAdvance=(real)f->ftfacemono->glyph->advance.x/64.0; if(glyph) FT_Done_Glyph(glyph); } glClearTexImage(f->TexBuffer.GLTexHandle, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); } tnsFontSingleCharacter *tfntFetchCharTextureIDW(uint32_t ch, int UseMono); const char* TNS_FONT_LOAD_OPTIONS[9]={"./","fonts/","lagui/fonts/","../","../fonts/","../lagui/fonts/","../../","../../fonts/","../../lagui/fonts/"}; int tnsLoadSystemFontMono(char* from, char* mono){ char buf[1024]; if(!FM->UsingFont || !mono || !mono[0]) return 0; tnsFont *f=FM->UsingFont; int GenHeight=LA_RH*MAIN.FontSize; int full_adv=0,half_adv=0; for(int i=0;iNumFaces;i++){ if(!FT_Get_Advance(f->ftface[i],L'我',FT_LOAD_TARGET_NORMAL | FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP, &full_adv)) break; } for(int i=-1;i<9;i++){ char* option=(i<0)?from:TNS_FONT_LOAD_OPTIONS[i]; sprintf(buf,"%s%s",option,mono); if (FT_New_Face(f->ftlib, buf, 0, &f->ftfacemono)) continue; FT_Select_Charmap(f->ftfacemono, FT_ENCODING_UNICODE); FT_Set_Char_Size(f->ftfacemono, 0, GenHeight << 6, 96, 96); if(!FT_Get_Advance(f->ftfacemono,'a',FT_LOAD_TARGET_NORMAL | FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP, &half_adv)){ f->MonoScale=(real)full_adv/(half_adv*2); FT_Set_Char_Size(f->ftfacemono, 0, (GenHeight << 6)*f->MonoScale, 96, 96); logPrint("Monospace font scale: %.2f\n",f->MonoScale); FT_Glyph glyph; if (FT_Load_Char(f->ftfacemono, 'a', FT_LOAD_TARGET_NORMAL | FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP)|| FT_Get_Glyph(f->ftfacemono->glyph, &glyph)){ SEND_PANIC_ERROR("Monospace font doesn't contain character 'a'"); } f->MonoAdvance=(real)f->ftfacemono->glyph->advance.x/64.0; if(glyph) FT_Done_Glyph(glyph); } return 1; } return 0; }; int tnsLoadSystemFont(char* from, char* name){ char buf[1024]; tnsFont *f=FM->UsingFont; if(!f){ f = CreateNew(tnsFont); f->characters=calloc(1, sizeof(tnsFontSingleCharacter*)*TNS_UNICODE_COUNT); f->monocharacters=calloc(1, sizeof(tnsFontSingleCharacter*)*TNS_MONO_COUNT); f->height = LA_RH*(MAIN.FontSize/2.0f+0.5f); tnsInit2DTexture(&f->TexBuffer, GL_RED, TNS_FONT_BUFFER_W, TNS_FONT_BUFFER_H, 0); lstAppendItem(&FM->Fonts, f); FM->UsingFont=f; if (FT_Init_FreeType(&f->ftlib)) SEND_PANIC_ERROR("Freetype Init Failed!"); } int GenHeight=LA_RH*MAIN.FontSize; for(int i=-1;i<9;i++){ char* option=(i<0)?from:TNS_FONT_LOAD_OPTIONS[i]; sprintf(buf,"%s%s",option,name); if (FT_New_Face(f->ftlib, buf, 0, &f->ftface[f->NumFaces])) continue; FT_Select_Charmap(f->ftface[f->NumFaces], FT_ENCODING_UNICODE); FT_Set_Char_Size(f->ftface[f->NumFaces], 0, GenHeight << 6, 96, 96); f->NumFaces++; return 1; } return 0; }; int tnsLoadVectorGraphPackage(const char *name, unsigned int size){ char i; tnsFont *f = CreateNew(tnsFont); f->height = (int)((real)size * 1.4); f->fontName = name; if (FT_Init_FreeType(&f->ftlib)) SEND_PANIC_ERROR("Can't Load Main Font:Freetype Init Failed!"); if (FT_New_Face(f->ftlib, name, 0, &f->ftface)) SEND_PANIC_ERROR("Can't Load Main Font:Freetype Can't Init Face"); FT_Select_Charmap(f->ftface, FT_ENCODING_UNICODE); FT_Set_Char_Size(f->ftface, size << 6, size << 6, 96, 96); //tnsInit2DTexture(&f->TexBuffer, GL_ALPHA, TNS_FONT_BUFFER_W, TNS_FONT_BUFFER_H, 0); //lstAppendItem(&FM->Fonts, f); //tnsUseFont(name); FM->VectorsGrapghs = f; }; int tfntBufferWidthEnough(int total_width, int current_width, int this_width){ return (current_width + this_width +1 < total_width); } void tfntApplyCharacterBufferOffset(tnsFont *f, tnsFontSingleCharacter *fsc){ if (!tfntBufferWidthEnough(TNS_FONT_BUFFER_W, f->CurrentX, fsc->width)){ f->CurrentY += (f->height+1); f->CurrentX = 0; } fsc->bufferx = f->CurrentX; fsc->buffery = f->CurrentY; f->CurrentX += (fsc->width+1); } tnsFontSingleCharacter *tfntFetchVectorGraphTextureIDW(uint32_t ID){ //GLuint revel = 0; //tnsFont *f = FM->VectorsGrapghs; //tnsFontSingleCharacter *fsc = 0; //FT_Glyph glyph = 0; //FT_BitmapGlyph bitmap_glyph; //FT_Bitmap bm; //FT_Face face; //int w, h, i, j; //GLubyte *buf = 0; //int a; //int Size = ((int)(_ICON_SYMBOL_SIZE[ID - 0)) << 6; //int ret; //if (!f) // return 0; //if (revel = f->icons[ID].Generated) // return &f->icons[ID]; //FT_Set_Char_Size(f->ftface, Size, Size, 96, 96); //if (ret = FT_Load_Char(f->ftface, ID, FT_LOAD_TARGET_NORMAL | FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP)) // return 0; //fsc = &f->icons[ID]; //face = f->ftface; //if (FT_Get_Glyph(face->glyph, &glyph)) // return 0; //FT_Render_Glyph(face->glyph, FT_RENDER_MODE_NORMAL); //FT_Glyph_To_Bitmap(&glyph, FT_RENDER_MODE_NORMAL, 0, 1); //bitmap_glyph = glyph; //bm = bitmap_glyph->bitmap; //w = bm.width; //h = bm.rows; //fsc->width = w; //fsc->height = h; //fsc->advx = face->glyph->advance.x / 64.0f; //fsc->advy = face->size->metrics.y_ppem; //fsc->deltax = bitmap_glyph->left; //fsc->deltay = bitmap_glyph->top - h; ////tfntApplyCharacterBufferOffset(f, fsc); ////glBindTexture(GL_TEXTURE_2D, f->TexBuffer.GLTexHandle); //buf = CreateNewBuffer(GLubyte, w * h); //for (j = 0; j < h; j++) //{ // for (i = 0; i < w; i++) // { // char _vl = bm.buffer[i + w * j]; // buf[i + (h - j - 1) * w] = _vl; // } //} //glPixelStorei(GL_UNPACK_ALIGNMENT, 1); //fsc->Tex = tnsCreate2DTexture(GL_ALPHA, w, h, buf); //glBindTexture(GL_TEXTURE_2D, 0); ////glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, w, h, 0, GL_ALPHA, GL_UNSIGNED_BYTE, buf); //glBindTexture(GL_TEXTURE_2D, 0); //FreeMem(buf); //fsc->Generated = 1; //return fsc; } tnsFontSingleCharacter *tfntFetchCharTextureIDW(uint32_t ch, int UseMono){ GLuint revel = 0; tnsFont *f = FM->UsingFont; tnsFontSingleCharacter **use_fsc=UseMono?f->monocharacters:f->characters, *fsc = 0; FT_Glyph glyph = 0; FT_BitmapGlyph bitmap_glyph; FT_Bitmap bm; FT_Face face; int w, h, i, j; GLubyte *buf = 0; if (!f) return 0; if(ch>TNS_MONO_COUNT){ UseMono=0; use_fsc=f->characters; } if(ch>TNS_UNICODE_COUNT){ return 0; } fsc = use_fsc[ch]; if(!fsc){ fsc=use_fsc[ch]=calloc(1,sizeof(tnsFontSingleCharacter)); } if (revel = fsc->Generated) return fsc; if(UseMono && f->ftfacemono){ face = f->ftfacemono; if(!FT_Get_Char_Index(face,ch)){return 0;} if (FT_Load_Char(face, ch, FT_LOAD_TARGET_NORMAL | FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP)){ return 0; } if (FT_Get_Glyph(face->glyph, &glyph)){ return 0; } }else{ for(int i=0;iNumFaces;i++){ if(!f->ftface[i]){continue;} face = f->ftface[i]; if(!FT_Get_Char_Index(face,ch)){continue;} if (FT_Load_Char(face, ch, FT_LOAD_TARGET_NORMAL | FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP)){ continue; } if (FT_Get_Glyph(face->glyph, &glyph)){ continue; } break; } if(!glyph){ return 0; } } FT_Render_Glyph(face->glyph, FT_RENDER_MODE_NORMAL); FT_Glyph_To_Bitmap(&glyph, FT_RENDER_MODE_NORMAL, 0, 1); bitmap_glyph = glyph; bm = bitmap_glyph->bitmap; w = bm.width; h = bm.rows; fsc->width = w; fsc->height = h; fsc->advx = (real)face->glyph->advance.x / 64.0f; fsc->advy = face->size->metrics.y_ppem; fsc->deltax = bitmap_glyph->left; fsc->deltay = bitmap_glyph->top - h; tfntApplyCharacterBufferOffset(f, fsc); tnsBindTexture(&f->TexBuffer); //glBindTexture(GL_TEXTURE_2D, f->TexBuffer.GLTexHandle); buf = CreateNewBuffer(GLubyte, w * h); for (j = 0; j < h; j++){ for (i = 0; i < w; i++){ char _vl = bm.buffer[i + w * j]; buf[i + (h - j - 1) * w] = _vl; } } glPixelStorei(GL_UNPACK_ALIGNMENT, 1); glTexSubImage2D(GL_TEXTURE_2D, 0, fsc->bufferx, fsc->buffery, w, h, GL_RED, GL_UNSIGNED_BYTE, buf); FreeMem(buf); FT_Done_Glyph(glyph); fsc->Generated = 1; return fsc; } tnsFontSingleCharacter *tfntFetchCharacterW(uint32_t ch, int UseMono){ tnsFontSingleCharacter* fsc = tfntFetchCharTextureIDW(ch, UseMono); if(fsc) return fsc; return tfntFetchCharTextureIDW('?', UseMono); } int CMP_NAME_IsThisFont(tnsFont *enumed, char *name){ return (!strcmp(enumed->fontName, name)); }; int tnsStringGetDimension(char* content, uint32_t* contentU, int Count, int WLimit, int* Rows, int UseMono){ real sx = 0; int sy = FM->UsingFont->height; real MA=FM->UsingFont->MonoAdvance; int i, rows=1, advance=1; int C = 0; int len = contentU?strlenU(contentU):(content?strlen(content):0); char hb; int RestoreI; int MaxSX=0; if(!WLimit){WLimit=INT_MAX;} int UC=1; for (i = 0; i < len && UC; i+=advance){ UC = contentU?contentU[i]:laToUnicode(&content[i], &advance); tnsFontSingleCharacter *fsc; if (UC == L'\n'){ if(sx>MaxSX) MaxSX=sx; sx = 0; sy += LA_RH; rows++; continue; }else{ fsc = tfntFetchCharacterW(UC, UseMono); real dx=fsc->advx; if(UseMono){ dx/=MA; if(dx<1.01) dx=1; if(dx>1.01)dx=2; dx*=MA; } if(sx+dx > WLimit){ sx = 0; sy += LA_RH; rows++; } sx += dx; C += 1; if (Count && C == Count) break; } } if(sx==0 && rows>1){rows--;} if(sx>MaxSX) MaxSX=sx; if(Rows) (*Rows)=rows; return MaxSX+1; } int tnsStringGetWidth(char *content, int Count, int UseMono){ return tnsStringGetDimension(content, 0, Count, 0, 0, UseMono); } int tnsStringGetWidthU(uint32_t *contentU, int Count, int UseMono){ return tnsStringGetDimension(0, contentU, Count, 0, 0, UseMono); } void tnsDrawStringM(char *content, uint32_t* contentU, real Color[4], int L, int R, int T, int Flags){ real sx = L; int sy = (LA_RH!=LA_RH0)?(((((real)FM->UsingFont->height/LA_RH0-0.5)/MAIN.UiScale)+0.5)*LA_RH + T):(FM->UsingFont->height+T); real MA=FM->UsingFont->MonoAdvance; int i,advance=1; int len = contentU?strlenU(contentU):strlen(content); real xo, yo, xl, yl; real TexCoord[12]; real VertArr[12]; int total_width = 0; tnsFont *f = FM->UsingFont; int FscHeight, RestoreI; int RevY=(Flags&LA_TEXT_REVERT_Y); int UseMono=(Flags&LA_TEXT_MONO); int OneLine=(Flags&LA_TEXT_ONE_LINE); int any=0, UC=1; int BreakNow=0; for (i = 0; i < len && UC; i+=advance){ UC = contentU?contentU[i]:laToUnicode(&content[i], &advance); tnsFontSingleCharacter *fsc; real cx, cy; if (UC == L'\n'){ if(!OneLine){sx = L; sy += LA_RH; continue;}else{ UC=' '; } } fsc = tfntFetchCharacterW(UC, Flags&LA_TEXT_MONO); real dx=fsc->advx; if(UseMono){ dx/=MA; if(dx<1.01) dx=1; if(dx>1.01)dx=2; dx*=MA; } if (sx + dx > R+1){ if(Flags&LA_TEXT_LINE_WRAP){ sx=L; sy+=LA_RH; }else{ if(Flags&LA_TEXT_OVERFLOW_ARROW){ fsc = tfntFetchCharacterW(L'▷', 0); sx=R-fsc->advx; BreakNow=1; } else break; } } cx = sx + fsc->deltax; cy = sy - fsc->deltay; xo = (real)fsc->bufferx / (real)TNS_FONT_BUFFER_W; yo = (real)fsc->buffery / (real)TNS_FONT_BUFFER_H; xl = (real)(fsc->bufferx + fsc->width) / (real)TNS_FONT_BUFFER_W; yl = (real)(fsc->buffery + fsc->height) / (real)TNS_FONT_BUFFER_H; tnsMakeQuadT2d(TexCoord, xo, yl, xo, yo, xl, yl, xl, yo); if (RevY) tnsMakeQuadT2d(VertArr, cx, 2 * T - cy + fsc->height, cx, 2 * T - cy, cx + fsc->width, 2 * T - cy + fsc->height, cx + fsc->width, 2 * T - cy); else tnsMakeQuadT2d(VertArr, cx, +cy - fsc->height, cx, +cy, cx + fsc->width, +cy - fsc->height, cx + fsc->width, +cy); tnsUseMaskTexture(&f->TexBuffer); tnsColor4dv(Color); tnsVertexArray2d(VertArr, 6); tnsTexCoordArray2d(TexCoord, 6); any=1; sx += dx; if(BreakNow){ break; } } if(any) tnsPackAs(GL_TRIANGLES); } void tnsDrawStringAutoM(char *content, uint32_t* contentU, real Color[4], int L, int R, int T, int Flags){ int LL; int al = Flags&LA_TEXT_ALIGN; if (!content && !contentU) return; switch (al){ case LA_TEXT_ALIGN_AUTO: case LA_TEXT_ALIGN_CENTER: LL = L+(R-L-tnsStringGetDimension(content, contentU, 0, 0, 0, Flags&LA_TEXT_MONO)) / 2; if(LL W){ if (Str2W < W){ tnsDrawStringM(MajorContent, 0, Color, R - Str2W, R, T, Flags); tnsDrawStringM(Label, 0, Color, L, R - Str2W, T, Flags); }else tnsDrawStringM(MajorContent, 0, Color, L, R, T, Flags); }else{ int LL = L, ML; switch (TextAlign){ case LA_TEXT_ALIGN_CENTER: ML = L + Str1W + (W - (Str1W + Str2W)) / 2; break; case LA_TEXT_ALIGN_LEFT: ML = L + Str1W; break; default: case LA_TEXT_ALIGN_AUTO: case LA_TEXT_ALIGN_RIGHT: ML = R - Str2W; break; } tnsDrawStringM(Label, 0, Color, LL, R, T, Flags); tnsDrawStringM(MajorContent, 0, Color, ML, R, T, Flags); } } void tnsDrawIcon(uint32_t ID, real Color[4], int L,int R, int T, int Flags){ char buf[5]={0}; char* next; laToUTF8(ID,buf,&next); tnsDrawStringAuto(buf, Color, L,R,T,Flags); } //=====================================================================================[Object] tnsObject *tnsFindObject(char *Name, tnsObject *FromObj){ tnsObject *io; tnsObject *ro; laListHandle* l=FromObj?(&FromObj->ChildObjects):(&T->World.AllObjects); for (laListItemPointer*lip=l->pFirst;lip;lip=lip->pNext){ io=((l==&T->World.AllObjects)?lip:lip->p); if (strSame(io->Name->Ptr, Name)){ return io; } if (ro = tnsFindObject(Name, io)) return ro; } return 0; } void tnsExtractSelfTransformValue(tnsObject *o){ if (!o) return; tnsExtractLocation44d(o->SelfTransform, &o->Location[0], &o->Location[1], &o->Location[2]); tnsExtractXYZEuler44d(o->SelfTransform, &o->Rotation[0], &o->Rotation[1], &o->Rotation[2]); tnsExtractUniformScale44d(o->SelfTransform, &o->Scale); } void tnsExtractGlobalTransformValue(tnsObject *o){ if (!o) return; tnsExtractLocation44d(o->GlobalTransform, &o->GLocation[0], &o->GLocation[1], &o->GLocation[2]); tnsExtractXYZEuler44d(o->GlobalTransform, &o->GRotation[0], &o->GRotation[1], &o->GRotation[2]); tnsExtractUniformScale44d(o->GlobalTransform, &o->GScale); } void tnsCopyGlobalTransform(tnsObject *to, tnsObject *from){ memcpy(to->GlobalTransform, from->GlobalTransform, sizeof(tnsMatrix44d)); memcpy(to->GLocation, from->GLocation, sizeof(tnsVector3d)); memcpy(to->GRotation, from->GRotation, sizeof(tnsVector3d)); to->GScale = from->GScale; tnsGlobalTransformValueChanged(to); } void tnsSelfMatrixChanged(tnsObject* o, int ApplyToChild){ tnsMatrix44d mix; if (!o->ParentObject){ tnsMultiply44d(mix, o->SelfTransform, o->DeltaTransform); memcpy(o->GlobalTransform, mix, sizeof(tnsMatrix44d)); } else{ tnsMultiply44d(mix, o->ParentObject->GlobalTransform, o->SelfTransform); tnsMultiply44d(o->GlobalTransform, mix, o->DeltaTransform); } tnsExtractSelfTransformValue(o); tnsExtractGlobalTransformValue(o); if(ApplyToChild) for (laListItemPointer* li=o->ChildObjects.pFirst;li;li=li->pNext){ tnsSelfMatrixChanged(li->p,1); } } void tnsGlobalMatrixChanged(tnsObject* o, int ApplyToChild){ if (!o->ParentObject){ memcpy(o->SelfTransform, o->GlobalTransform, sizeof(tnsMatrix44d)); } else{ tnsMatrix44d inv; tnsInverse44d(inv, o->ParentObject->GlobalTransform); tnsMultiply44d(o->SelfTransform, inv, o->GlobalTransform); } tnsExtractSelfTransformValue(o); tnsExtractGlobalTransformValue(o); if(ApplyToChild) for (laListItemPointer* li=o->ChildObjects.pFirst;li;li=li->pNext){ tnsSelfMatrixChanged(li->p,1); } } void tnsSelfTransformValueChanged(tnsObject* o){ tnsMatrix44d Trans, Rot1, Rot2, Rot3, Scale, Res1, Res2; tnsLoadIdentity44d(o->SelfTransform); tnsMakeTranslationMatrix44d(Trans, LA_COLOR3(o->Location)); tnsMakeScaleMatrix44d(Scale, o->Scale,o->Scale,o->Scale); tnsMakeRotationXMatrix44d(Rot1, o->Rotation[0]); tnsMakeRotationYMatrix44d(Rot2, o->Rotation[1]); tnsMakeRotationZMatrix44d(Rot3, o->Rotation[2]); switch (o->RotationMode){ case TNS_ROTATION_ZYX_EULER: tnsMultiply44d(Res1, Trans, Rot1); tnsMultiply44d(Res2, Res1, Rot2); tnsMultiply44d(Res1, Res2, Rot3); break; case TNS_ROTATION_XZY_EULER: tnsMultiply44d(Res1, Trans, Rot1); tnsMultiply44d(Res2, Res1, Rot3); tnsMultiply44d(Res1, Res2, Rot2); break; case TNS_ROTATION_YXZ_EULER: tnsMultiply44d(Res1, Trans, Rot2); tnsMultiply44d(Res2, Res1, Rot1); tnsMultiply44d(Res1, Res2, Rot3); break; case TNS_ROTATION_YZX_EULER: tnsMultiply44d(Res1, Trans, Rot2); tnsMultiply44d(Res2, Res1, Rot3); tnsMultiply44d(Res1, Res2, Rot1); break; case TNS_ROTATION_ZXY_EULER: tnsMultiply44d(Res1, Trans, Rot3); tnsMultiply44d(Res2, Res1, Rot1); tnsMultiply44d(Res1, Res2, Rot2); break; case TNS_ROTATION_XYZ_EULER: tnsMultiply44d(Res1, Trans, Rot3); tnsMultiply44d(Res2, Res1, Rot2); tnsMultiply44d(Res1, Res2, Rot1); break; } tnsMultiply44d(o->SelfTransform, Res1, Scale); tnsSelfMatrixChanged(o,1); } void tnsGlobalTransformValueChanged(tnsObject* o){ tnsMatrix44d Trans, Rot1, Rot2, Rot3, Scale, Res1, Res2; tnsLoadIdentity44d(o->GlobalTransform); tnsMakeTranslationMatrix44d(Trans, LA_COLOR3(o->GLocation)); tnsMakeScaleMatrix44d(Scale, o->GScale,o->GScale,o->GScale); tnsMakeRotationXMatrix44d(Rot1, o->GRotation[0]); tnsMakeRotationYMatrix44d(Rot2, o->GRotation[1]); tnsMakeRotationZMatrix44d(Rot3, o->GRotation[2]); switch (o->RotationMode){ case TNS_ROTATION_ZYX_EULER: tnsMultiply44d(Res1, Trans, Rot1); tnsMultiply44d(Res2, Res1, Rot2); tnsMultiply44d(Res1, Res2, Rot3); break; case TNS_ROTATION_XZY_EULER: tnsMultiply44d(Res1, Trans, Rot1); tnsMultiply44d(Res2, Res1, Rot3); tnsMultiply44d(Res1, Res2, Rot2); break; case TNS_ROTATION_YXZ_EULER: tnsMultiply44d(Res1, Trans, Rot2); tnsMultiply44d(Res2, Res1, Rot1); tnsMultiply44d(Res1, Res2, Rot3); break; case TNS_ROTATION_YZX_EULER: tnsMultiply44d(Res1, Trans, Rot2); tnsMultiply44d(Res2, Res1, Rot3); tnsMultiply44d(Res1, Res2, Rot1); break; case TNS_ROTATION_ZXY_EULER: tnsMultiply44d(Res1, Trans, Rot3); tnsMultiply44d(Res2, Res1, Rot1); tnsMultiply44d(Res1, Res2, Rot2); break; case TNS_ROTATION_XYZ_EULER: tnsMultiply44d(Res1, Trans, Rot3); tnsMultiply44d(Res2, Res1, Rot2); tnsMultiply44d(Res1, Res2, Rot1); break; } tnsMultiply44d(o->GlobalTransform, Res1, Scale); tnsGlobalMatrixChanged(o,1); } void tnsSetCurrentRoot(tnsObject *o){ if(o->Type!=TNS_OBJECT_ROOT) return; T->World.ActiveRoot=o; // memAssignRef(s, &s->CurrentObject, o); we can't use this apparently because World is not hyper 2. // XXX: Needs fake mempool/user, or T->World prop redesign because T is runtime allocated. } void tnsInitObjectBase(tnsObject *o, tnsObject *under, char *Name, int Type, real AtX, real AtY, real AtZ, real RotX, real RotY, real RotZ, real RotW, u8bit RotationMode, real Scale){ if (!o) return; strSafeSet(&o->Name, Name); o->Type = Type; o->Location[0] = AtX; o->Location[1] = AtY; o->Location[2] = AtZ; o->Rotation[0] = RotX; o->Rotation[1] = RotY; o->Rotation[2] = RotZ; o->Rotation[3] = RotW; o->RotationMode = RotationMode; o->Scale = Scale; o->Show = 1; o->DrawMode = GL_LINE_LOOP; tnsLoadIdentity44d(o->DeltaTransform); tnsSelfTransformValueChanged(o); lstAppendItem(&T->World.AllObjects, o); if (under){ lstAppendPointer(&under->ChildObjects, o); tnsObject* root=under->Type==TNS_OBJECT_ROOT?under:under->InRoot; memAssignRef(o, &o->InRoot, root); } } int tnsCheckParentable(tnsObject* child, tnsObject* parent){ if(child==parent||parent->ParentObject==child)return 0; tnsObject* o=parent; while(o=o->ParentObject){ if(o==parent) return 0; } return 1; } void tnsParentObject(tnsObject *child, tnsObject *parent, int KeepTransform){ if (!child || !parent || child->ParentObject==parent || parent->ParentObject==child || parent==child) return; if (child->ParentObject) lstRemovePointerLeave(&child->ParentObject->ChildObjects, child); else lstRemovePointerLeave(&child->InRoot->ChildObjects, child); lstAppendPointer(&parent->ChildObjects, child); memAssignRef(child, &child->ParentObject, parent); if(KeepTransform) tnsGlobalMatrixChanged(child, 1); else tnsSelfMatrixChanged(child, 1); } void tnsUnparentObject(tnsObject *o, int KeepTransform){ if (!o || !o->ParentObject) return; lstRemovePointerLeave(&o->ParentObject->ChildObjects, o); lstAppendPointer(&o->InRoot->ChildObjects, o); memAssignRef(o, &o->ParentObject, 0); if(KeepTransform) tnsGlobalMatrixChanged(o,1); else tnsSelfMatrixChanged(o,1); } void tnsCopyObjectTransformationsLocal(tnsObject* to, tnsObject* from){ tnsVectorCopy3d(from->Location, to->Location); tnsVectorCopy3d(from->Rotation, to->Rotation); to->RotationMode=from->RotationMode; to->Scale = from->Scale; tnsSelfTransformValueChanged(to); } void tnsCopyObjectTransformationsGlobal(tnsObject* to, tnsObject* from){ tnsVectorCopy3d(from->GLocation, to->GLocation); tnsVectorCopy3d(from->GRotation, to->GRotation); to->RotationMode=from->RotationMode; to->GScale = from->GScale; tnsGlobalTransformValueChanged(to); } void tnsRotateObjectLocalValues(tnsObject *o, real x, real y, real z){ o->Rotation[0] += x; o->Rotation[1] += y; o->Rotation[2] += z; tnsSelfTransformValueChanged(o); } void tnsMoveObjectLocal(tnsObject *o, real x, real y, real z){ tnsMatrix44d mat, res1, res2, res3; tnsMakeTranslationMatrix44d(res2, x, y, z); tnsMultiply44d(res1, o->SelfTransform, res2); memcpy(o->SelfTransform, res1, sizeof(tnsMatrix44d)); tnsSelfMatrixChanged(o,1); } void tnsMoveObjectDelta(tnsObject *o, real x, real y, real z){ tnsMatrix44d mat, res1, res2, res3; tnsMakeTranslationMatrix44d(res2, x, y, z); tnsMultiply44d(res1, o->DeltaTransform, res2); memcpy(o->DeltaTransform, res1, sizeof(tnsMatrix44d)); tnsSelfMatrixChanged(o,1); } void tnsMoveObjectGlobal(tnsObject *o, real x, real y, real z){ tnsMatrix44d mat, res1, res2, res3; tnsMakeTranslationMatrix44d(res2, x, y, z); tnsMultiply44d(res1, res2, o->GlobalTransform); //if reverse then local memcpy(o->GlobalTransform, res1, sizeof(tnsMatrix44d)); tnsGlobalMatrixChanged(o,1); } void tnsRotateObjectGlobal(tnsObject *o, real x, real y, real z, real angle, real cx,real cy,real cz){ tnsMatrix44d tback,tfwd,rot,rot2,res1,res2; real xs, ys, zs; tnsMakeRotationMatrix44d(rot,angle,x,y,z); tnsMakeRotationMatrix44d(rot2,-angle,x,y,z);//why? tnsMakeTranslationMatrix44d(tfwd, o->GLocation[0],o->GLocation[1],o->GLocation[2]); tnsInverse44d(tback,tfwd); tnsMultiply44d(res1,o->GlobalTransform,tback); tnsMultiply44d(res2,rot,res1); tnsMultiply44d(o->GlobalTransform,res2,tfwd); tnsVector3d delta; delta[0]=o->GLocation[0]-cx; delta[1]=o->GLocation[1]-cy; delta[2]=o->GLocation[2]-cz; tnsVector3d c; c[0]=cx; c[1]=cy; c[2]=cz; tnsVector3d r; tnsApplyRotation43d(r,rot2,delta); tnsVectorPlus3d(&o->GlobalTransform[12],c,r); //memcpy(o->GlobalTransform, res1, sizeof(tnsMatrix44d)); tnsGlobalMatrixChanged(o,1); } void tnsRotateObjectLocal(tnsObject *o, real x, real y, real z, real angle, real gcx,real gcy,real gcz){ tnsMatrix44d tback,tfwd,rot,res1,res2; real xs, ys, zs; tnsVector3d gp,gpt; gp[0]=gcx; gp[1]=gcy; gp[2]=gcz; tnsApplyTransform43d(gpt,o->GlobalTransform,gp); tnsMakeTranslationMatrix44d(tfwd, gpt[0]-gcx, gpt[0]-gcy, gpt[0]-gcz); tnsInverse44d(tback,tfwd); tnsMakeRotationMatrix44d(rot,angle,x,y,z); tnsMultiply44d(res1,o->SelfTransform,tback); tnsMultiply44d(res2,res1,rot); tnsMultiply44d(o->SelfTransform,res2,tfwd); tnsSelfMatrixChanged(o,1); } void tnsRotateObjectDelta(tnsObject *o, real x, real y, real z, real angle, real gcx,real gcy,real gcz){ tnsMatrix44d tback,tfwd,rot,res1,res2; real xs, ys, zs; tnsVector3d gp,gpt; gp[0]=gcx; gp[1]=gcy; gp[2]=gcz; tnsApplyTransform43d(gpt,o->DeltaTransform,gp); tnsMakeTranslationMatrix44d(tfwd, gpt[0]-gcx, gpt[0]-gcy, gpt[0]-gcz); tnsInverse44d(tback,tfwd); tnsMakeRotationMatrix44d(rot,angle,x,y,z); tnsMultiply44d(res1,o->SelfTransform,tback); tnsMultiply44d(res2,res1,rot); tnsMultiply44d(o->SelfTransform,res2,tfwd); tnsSelfMatrixChanged(o,1); } void tnsScaleObject(tnsObject *o, real fac, real cx,real cy,real cz){ tnsMatrix44d sca,res1,res2; tnsMakeScaleMatrix44d(sca,fac,fac,fac); tnsMultiply44d(res1,o->GlobalTransform,sca); tnsVector3d delta; delta[0]=res1[12]-cx; delta[1]=res1[13]-cy; delta[2]=res1[14]-cz; tnsVector3d c; c[0]=cx; c[1]=cy; c[2]=cz; tnsVectorMultiSelf3d(delta, fac); tnsVectorPlus3d(&res1[12],c,delta); memcpy(o->GlobalTransform, res1, sizeof(tnsMatrix44d)); tnsGlobalMatrixChanged(o,1); } void tnsScaleObjectDelta(tnsObject *o, real fac, real cx,real cy,real cz){ tnsMatrix44d sca,res1,res2; tnsMakeScaleMatrix44d(sca,fac,fac,fac); tnsMultiply44d(res1,o->DeltaTransform,sca); tnsVector3d delta; delta[0]=res1[12]-cx; delta[1]=res1[13]-cy; delta[2]=res1[14]-cz; tnsVector3d c; c[0]=cx; c[1]=cy; c[2]=cz; tnsVectorMultiSelf3d(delta, fac); tnsVectorPlus3d(&res1[12],c,delta); memcpy(o->DeltaTransform, res1, sizeof(tnsMatrix44d)); tnsGlobalMatrixChanged(o,1); } void tnsZoomViewingCamera(tnsCamera *c, real Ratio){ if (c->FocusDistance < 0.1) return; tnsMoveObjectLocal(c, 0, 0, -c->FocusDistance * Ratio); c->FocusDistance *= (1 - Ratio); } void tnsRotateViewingCamera(tnsCamera *c, real x, real z){ tnsMoveObjectLocal(c, 0, 0, -c->FocusDistance); tnsRotateObjectLocalValues(c, x, 0, z); tnsMoveObjectLocal(c, 0, 0, c->FocusDistance); } void tnsGetCameraMovingDeltas(tnsCamera *c, int ViewportW, int ViewportH, real x, real y, tnsVector4d p){ memset(p, 0, sizeof(tnsVector4d)); tnsVector4d tp = {0}; tnsMatrix44d combine, projection, projinv, vpinv, vp; tnsLoadIdentity44d(projection); tnsMakePerspectiveMatrix44d(projection, c->FOV, (real)ViewportW / (real)ViewportH, c->ZMin, c->ZMax); tnsMakeViewportMatrix44d(vp, ViewportW, ViewportH, c->ZMax, c->ZMin); tnsInverse44d(projinv, projection); tnsInverse44d(vpinv, vp); p[2] = -c->FocusDistance; p[3] = 1; tnsApplyTransform44d(tp, projection, p); tnsVectorMultiSelf3d(tp, 1 / tp[3]); tnsApplyTransform43d(p, vp, tp); p[0] += x; p[1] += y; tnsApplyTransform43d(tp, vpinv, p); tnsVectorMultiSelf3d(tp, tp[3]); tnsApplyTransform44d(p, projinv, tp); } void tnsTranslateViewingCamera(tnsCamera *c, int ViewportW, int ViewportH, real x, real y){ tnsVector4d p={0}; tnsGetCameraMovingDeltas(c,ViewportW, ViewportH, x,y,p); tnsMoveObjectLocal(c, p[0], p[1], 0); } tnsObject *tnsCreateRootObject(char *name){ tnsWorld *w = &T->World; tnsObject *o = memAcquireHyper(sizeof(tnsObject)); o->Type==TNS_OBJECT_ROOT; strSafeSet(&o->Name, name); lstAppendItem(&w->RootObjects, o); w->ActiveRoot = o; // XXX: same here return o; } void tnsDestroyRootObject(tnsObject *root){ tnsWorld *w = &T->World; tnsObject *o, *NextO; w->ActiveRoot = root->Item.pPrev ? root->Item.pPrev : root->Item.pNext ? root->Item.pNext : 0; lstRemoveItem(&w->RootObjects, root); while (lstPopPointerLeave(&root->ChildObjects)); strSafeDestroy(&root->Name); memLeave(root); } void tnsDestroyObject(tnsObject *o){ if(o->Type==TNS_OBJECT_ROOT){ tnsDestroyRootObject(o); return; } tnsUnparentObject(o,1); while(o->ChildObjects.pFirst){ tnsUnparentObject(((laListItemPointer*)o->ChildObjects.pFirst)->p, 1); } lstRemoveItem(&T->World.AllObjects, o); if(o->Type==TNS_OBJECT_MESH){ tnsMeshObject* mo=o; if(mo->v) arrFree(&mo->v, &mo->maxv); if(mo->e) arrFree(&mo->e, &mo->maxe); if(mo->f){ for(int i=0;itotf;i++){ free(mo->f[i].loop); } arrFree(&mo->f, &mo->maxf); } mo->totv=mo->tote=mo->totf=0; tnsInvalidateMeshBatch(o); } strSafeDestroy(&o->Name); memLeave(o); } tnsCamera *tnsCreateCamera(tnsObject *under, char *Name, real FOV, real AtX, real AtY, real AtZ, real RotX, real RotY, real RotZ, real FocusDistance){ tnsCamera *c; tnsWorld *w = &T->World; c = memAcquireHyper(sizeof(tnsCamera)); tnsInitObjectBase(&c->Base, under, Name, TNS_OBJECT_CAMERA, AtX, AtY, AtZ, RotX, RotY, RotZ, 1.0f, TNS_ROTATION_XYZ_EULER, 1.0f); c->FOV = FOV; c->CameraType = TNS_PRESPECTIVE_CAMERA; c->ZMin = 0.1f; c->ZMax = 1000.0f; c->FocusDistance = FocusDistance; c->OrthScale = 1.0f; return c; } tnsObject *tnsCreateEmpty(tnsObject *under, char *Name, real AtX, real AtY, real AtZ){ tnsObject *o; tnsWorld *w = &T->World; if (!under) return 0; o = memAcquireHyper(sizeof(tnsObject)); tnsInitObjectBase(o, under, Name, TNS_OBJECT_EMPTY, AtX, AtY, AtZ, 0, 0, 0, 1.0f, TNS_ROTATION_XYZ_EULER, 1.0f); return o; } tnsLight *tnsCreateLight(tnsObject *under, char *Name, real AtX, real AtY, real AtZ, real Strength, int UniDirectional){ tnsLight *l; tnsWorld *w = &T->World; if (!under) return 0; tnsObject* root=under->Type==TNS_OBJECT_ROOT?under:under->InRoot; if (UniDirectional&&under){ if(root){ if(root->ParentObject) return root->ParentObject; } } l = memAcquireHyper(sizeof(tnsLight)); tnsInitObjectBase(&l->Base, under, Name, TNS_OBJECT_LIGHT, AtX, AtY, AtZ, 0, 0, 0, 1.0f, TNS_ROTATION_XYZ_EULER, 1.0f); l->Strength = Strength; l->UniDirectional = UniDirectional; if (root && UniDirectional && !root->ParentObject) memAssignRef(root, &root->ParentObject,l); return l; } int tnsAnyObjectsSelected(tnsObject *root){ for(laListItemPointer* lip=root->ChildObjects.pFirst;lip;lip=lip->pNext){ tnsObject* o=lip->p; if(o->Flags&TNS_OBJECT_FLAGS_SELECTED) return 1; if(o->ChildObjects.pFirst && tnsAnyObjectsSelected(o)) return 1; } return 0; } void tnsDeselectAllObjects(tnsObject *root){ for(laListItemPointer* lip=root->ChildObjects.pFirst;lip;lip=lip->pNext){ tnsObject* o=lip->p; o->Flags&=(~TNS_OBJECT_FLAGS_SELECTED); if(o->ChildObjects.pFirst)tnsDeselectAllObjects(o); } } void tnsSelectAllObjects(tnsObject *root){ for(laListItemPointer* lip=root->ChildObjects.pFirst;lip;lip=lip->pNext){ tnsObject* o=lip->p; o->Flags|=TNS_OBJECT_FLAGS_SELECTED; if(o->ChildObjects.pFirst)tnsSelectAllObjects(o); } } void tnsSelectObject(tnsObject* o, int Select, int Toggle){ if(!o) return; if(Toggle) tnsSelectObject(o,(o->Flags&TNS_OBJECT_FLAGS_SELECTED?0:1),0); elif(Select) o->Flags|=TNS_OBJECT_FLAGS_SELECTED; else o->Flags&=(~TNS_OBJECT_FLAGS_SELECTED); } void tnsGetCameraProjection(tnsMatrix44d* mat, int w, int h, tnsCamera* Camera){ tnsMatrix44d inv, result; tnsMakePerspectiveMatrix44d(mat, Camera->FOV, (real)w / (real)h, Camera->ZMin, Camera->ZMax); } void tnsGetCameraViewProjection(tnsMatrix44d* mat, int w, int h, tnsCamera* Camera){ tnsMatrix44d inv, result; tnsMakePerspectiveMatrix44d(mat, Camera->FOV, (real)w / (real)h, Camera->ZMin, Camera->ZMax); tnsInverse44d(inv, Camera->Base.GlobalTransform); tnsMultiply44d(result, mat, inv); memcpy(mat, result, sizeof(tnsMatrix44d)); } void tnsApplyCameraView(int W, int H, tnsCamera *Camera){ tnsMatrixStackItem *tmsi = tKnlGetCurrentMatStackItem(); tnsShader *current_shader = 0; real *mat; tnsMatrix44d result, inv; if (!Camera) return; mat = tnsGetProjectionMatrix(); tnsMakePerspectiveMatrix44d(mat, Camera->FOV, (real)W / (real)H, Camera->ZMin, Camera->ZMax); if (current_shader = tKnlGetActiveShader()){ tnsShaderApplyProjection(current_shader, mat); tnsShaderApplyProjectionInverse(current_shader, mat); } tnsResetViewMatrix(); mat = tnsGetViewMatrix(); tnsInverse44d(inv, Camera->Base.GlobalTransform); tnsMultiply44d(result, mat, inv); memcpy(mat, result, sizeof(tnsMatrix44d)); if (current_shader = tKnlGetActiveShader()){ tnsShaderApplyView(current_shader, result); if(current_shader->uViewPos>-1) glUniform3f(current_shader->uViewPos,LA_COLOR3(Camera->Base.Location)); } } void tnsApplyShadowCameraView(tnsLight *Light){ tnsMatrixStackItem *tmsi = tKnlGetCurrentMatStackItem(); tnsShader *current_shader = 0; tnsMatrix44d mat; tnsMatrix44d result, inv; if (!Light || !Light->UniDirectional) return; //mat = tnsGetProjectionMatrix(); tnsMakeOrthoMatrix44d(mat, -1000,1000,-1000,1000,-1000,1000); tnsInverse44d(inv, Light->Base.GlobalTransform); tnsMultiply44d(result, mat, inv); memcpy(mat, result, sizeof(tnsMatrix44d)); if (current_shader = tKnlGetActiveShader()){ tnsShaderApplyShadowMatrix(current_shader,mat); } } void tnsApplyObjectMatrix(tnsObject *Object){ tnsShader *current_shader = 0; real *mat; tnsMatrix44d result; if (!Object) return; mat = tnsGetModelMatrix(); //tnsMultiply44d(result, mat, Object->SelfTransform); memcpy(mat, Object->GlobalTransform, sizeof(tnsMatrix44d)); //Actually This Works Pretty Fast,but we are currently testing its functionality; //memcpy(mat, Object->GlobalTransform, sizeof(tnsMatrix44d)); if (current_shader = tKnlGetActiveShader()){ tnsShaderApplyModel(current_shader, mat); } } void tnsLookAt(tnsObject *o, tnsVector3d Target, tnsVector3d Up){ tnsVector4d target = {0}; tnsMatrix44d mat, res, res2; real *d; tnsShader *current_shader = 0; d = tnsGetModelMatrix(); tnsMakeZTrackingMatrix44d(mat, o->GLocation, target, Up); tnsLoadIdentity44d(res); tnsMakeTranslationMatrix44d(res,o->GLocation[0],o->GLocation[1],o->GLocation[2]); tnsMultiply44d(res2, res, mat); memcpy(o->SelfTransform, res2, sizeof(tnsMatrix44d)); tnsSelfMatrixChanged(o,1); if (current_shader = tKnlGetActiveShader()){ tnsShaderApplyModel(current_shader, d); } } void tnsDrawCamera(tnsObject *o){ tnsCamera *c = o; real fov_2 = c->FOV / 2; real ex, ey, ez; ey = 10 * sin(fov_2); ex = ey; ez = 10 * cos(fov_2); //if (T->CurrentShader != T->uiShader) tnsEnableShaderv(T->uiShader); tnsColor4d(1, 1, 1, 1); tnsVertex3d(ex, ey, -ez); tnsVertex3d(ex, -ey, -ez); tnsVertex3d(0.0, 0.0, 0.0); tnsVertex3d(ex, ey, -ez); tnsVertex3d(-ex, ey, -ez); tnsVertex3d(0.0, 0.0, 0.0); tnsVertex3d(-ex, -ey, -ez); tnsVertex3d(-ex, ey, -ez); tnsPackAs(GL_LINE_STRIP); tnsFlush(); } void tnsDrawCross(real x,real y,real z,real x1,real x2,real y1,real y2,real z1,real z2){ tnsVertex3d(x+x1, y+0.0, z+0.0); tnsVertex3d(x+x2, y+0.0, z+0.0); tnsVertex3d(x+0.0,y+ y1, z+0.0); tnsVertex3d(x+0.0,y+ y2, z+0.0); tnsVertex3d(x+0.0,y+ 0.0,z+ z1); tnsVertex3d(x+0.0,y+ 0.0,z+ z2); } void tnsDrawPlaceholder(tnsObject* o, tnsObject *active, int DrawAsSelection){ if(T->BindedShader==T->SelectionShader){ int i=o->SelectID; real color[4]={0,0,0,1}; TNS_ID_TO_COLOR(color,i); tnsColor4dv(color); }else{ if(DrawAsSelection && (!(o->Flags&TNS_OBJECT_FLAGS_SELECTED))) return; if(!DrawAsSelection && (o->Flags&TNS_OBJECT_FLAGS_SELECTED)) return; if(o==active){ tnsColor4dv(laAccentColor(LA_BT_TEXT_ACTIVE)); } elif(o->Flags&TNS_OBJECT_FLAGS_SELECTED){ tnsColor4dv(laAccentColor(LA_BT_NORMAL)); } else tnsColor4dv(laThemeColor(_LA_THEME_3D_VIEW,LA_BT_BORDER)); } tnsDrawCross(0,0,0,-1,5,-1,5,-1,5); tnsPackAs(GL_LINES); tnsFlush(); } void tnsDrawThisObject(tnsObject *o,tnsObject *active, int DrawAsObjectSelection, int MeshSelectionMode){ if (!o->Show) return; switch (o->Type){ case TNS_OBJECT_MESH: tnsDrawMeshObject(o, DrawAsObjectSelection, MeshSelectionMode, active); break; case TNS_OBJECT_CAMERA: tnsDrawCamera(o); break; case TNS_OBJECT_EMPTY: default: tnsDrawPlaceholder(o,active,DrawAsObjectSelection); break; } } void tnsDrawObjectTree(tnsObject *from, tnsObject *active, int DrawAsObjectSelection, int MeshSelectionMode){ tnsObject *o; if(!from) return; for (laListItemPointer* lip=from->ChildObjects.pFirst;lip;lip=lip->pNext){ o=lip->p; tnsPushMatrix(); tnsApplyObjectMatrix(o); tnsDrawThisObject(o, active, DrawAsObjectSelection, MeshSelectionMode); if (o->ChildObjects.pFirst){ tnsDrawObjectTree(o, active, DrawAsObjectSelection, MeshSelectionMode); } tnsPopMatrix(); } } void tnsDrawObjectOrigins(tnsObject *from, tnsObject *active, int AllOrigins){ tnsObject *o; if(!from) return; tnsVector4d pos; for (laListItemPointer* lip=from->ChildObjects.pFirst;lip;lip=lip->pNext){ o=lip->p; if((!AllOrigins) && (o!=active) && (!(o->Flags&TNS_OBJECT_FLAGS_SELECTED))) continue; if(o->Type==TNS_OBJECT_MESH && ((tnsMeshObject*)o)->Mode==TNS_MESH_EDIT_MODE){ continue; } if(T->BindedShader==T->SelectionShader){ int i=o->SelectID; real color[4]={0,0,0,1}; TNS_ID_TO_COLOR(color,i); tnsColor4dv(color); } else{ if(o==active){ tnsColor4dv(laAccentColor(LA_BT_TEXT_ACTIVE)); } elif(o->Flags&TNS_OBJECT_FLAGS_SELECTED){ tnsColor4dv(laAccentColor(LA_BT_NORMAL)); } else{ real* c=laThemeColor(_LA_THEME_3D_VIEW,LA_BT_BORDER); tnsColor4d(LA_COLOR3(c),0.5); } } tnsVertex3d(LA_COLOR3(o->GLocation)); tnsPackAs(GL_POINTS); } } void tnsDrawCursor(tnsObject* root){ if(root->Type!=TNS_OBJECT_ROOT) return; tnsMatrix44d vp; tnsVector4d t; tnsVector4d t1={0,0,0,1}; tnsMultiply44d(vp,tnsGetProjectionMatrix(),tnsGetViewMatrix()); tnsApplyTransform44d(t,vp,root->GLocation); real w=t[3]*0.05; tnsDrawCross(LA_COLOR3(root->GLocation),-w,w,-w,w,-w,w); tnsColor4d(0,0,0,0.5); tnsPackAs(GL_LINES); glLineWidth(5); tnsFlush(); w*=0.9; tnsDrawCross(LA_COLOR3(root->GLocation),-w,w,-w,w,-w,w); tnsColor4dv(laThemeColor(_LA_THEME_3D_VIEW,LA_BT_BORDER)); tnsPackAs(GL_LINES); glLineWidth(2); tnsFlush(); glLineWidth(1); } //===================================================================[Material] tnsMaterial *tnsCreateMaterial(char *Name){ tnsMaterial *m; if(!Name || !Name[0]) return 0; m = memAcquireHyper(sizeof(tnsMaterial)); strSafeSet(&m->Name, Name); lstAppendItem(&T->World.Materials, m); return m; } tnsMaterial *tnsFindMaterialByIndex(int index){ tnsMaterial *m; int i = 0; for (m = T->World.Materials.pFirst; m; m = m->Item.pNext){ if (i == index){ m->ID = i; return m; } i++; } return 0; } tnsMaterial *tnsFindMaterial(char *name){ tnsMaterial *m; int i = 0; for (m = T->World.Materials.pFirst; m; m = m->Item.pNext){ if (strSame(m->Name->Ptr, name)){ return m; } } return 0; } //==================================================================[Util] #define MAX3(a, b, c) \ a > b ? (a > c ? a : c) : (b > c ? b : c) #define MIN3(a, b, c) \ a < b ? (a < c ? a : c) : (b < c ? b : c) extern LA MAIN; void tnssRGB2XYZ(tnsVector3d rgb,tnsVector3d xyz){ tnsMatrix44d mat={{0.4124564,0.3575761,0.1804375,0}, {0.2126729,0.7151522,0.0721750,0}, {0.0193339,0.1191920,0.9503041,0},{0,0,0,0}}; tnsApplyRotation33d(xyz,mat,rgb); } void tnsClay2XYZ(tnsVector3d rgb,tnsVector3d xyz){ tnsMatrix44d mat={{0.5767309,0.1855540,0.1881852,0}, {0.2973769,0.6273491,0.0752741,0}, {0.0270343,0.0706872,0.9911085,0},{0,0,0,0}}; tnsApplyRotation33d(xyz,mat,rgb); } void tnsXYZ2sRGB(tnsVector3d xyz,tnsVector3d rgb){ tnsMatrix44d mat={{3.2404542,-1.5371385,-0.4985314,0}, {-0.9692660,1.8760108,0.0415560,0}, {0.0556434,-0.2040259,1.0572252,0},{0,0,0,0}}; tnsApplyRotation33d(rgb,mat,xyz); } void tnsXYZ2Clay(tnsVector3d xyz,tnsVector3d rgb){ tnsMatrix44d mat={{2.0413690,-0.5649464,-0.3446944}, {-0.9692660,1.8760108,0.0415560}, {0.0134474,-0.1183897,1.0154096},{0,0,0,0}}; tnsApplyRotation33d(rgb,mat,xyz); } static real _srgb_transfer_function(real a){ return .0031308f >= a ? 12.92f * a : 1.055f * powf(a, .4166666666666667f) - .055f; } static real _srgb_transfer_function_inv(real a){ return .04045f < a ? powf((a + .055f) / 1.055f, 2.4f) : a / 12.92f; } void tns2LogsRGBSingle(real* a){ *a=_srgb_transfer_function(*a); } void tns2LinearsRGBSingle(real* a){ *a=_srgb_transfer_function_inv(*a); } void tns2LogsRGB(real* srgb){ srgb[0]=_srgb_transfer_function(srgb[0]); srgb[1]=_srgb_transfer_function(srgb[1]); srgb[2]=_srgb_transfer_function(srgb[2]); } void tns2LinearsRGB(real* srgb){ srgb[0]=_srgb_transfer_function_inv(srgb[0]); srgb[1]=_srgb_transfer_function_inv(srgb[1]); srgb[2]=_srgb_transfer_function_inv(srgb[2]); } void tnsRGB2OKLAB(real* rgb, real* oklab){ real l = 0.4122214708f * rgb[0] + 0.5363325363f * rgb[1] + 0.0514459929f * rgb[2]; real m = 0.2119034982f * rgb[0] + 0.6806995451f * rgb[1] + 0.1073969566f * rgb[2]; real s = 0.0883024619f * rgb[0] + 0.2817188376f * rgb[1] + 0.6299787005f * rgb[2]; real l_ = cbrt(l); real m_ = cbrt(m); real s_ = cbrt(s); oklab[0]=0.2104542553f*l_ + 0.7936177850f*m_ - 0.0040720468f*s_; oklab[1]=1.9779984951f*l_ - 2.4285922050f*m_ + 0.4505937099f*s_; oklab[2]=0.0259040371f*l_ + 0.7827717662f*m_ - 0.8086757660f*s_; } void tnsOKLAB2RGB(real* oklab, real* rgb){ real l_ = oklab[0] + 0.3963377774f * oklab[1] + 0.2158037573f * oklab[2]; real m_ = oklab[0] - 0.1055613458f * oklab[1] - 0.0638541728f * oklab[2]; real s_ = oklab[0] - 0.0894841775f * oklab[1] - 1.2914855480f * oklab[2]; real l = l_*l_*l_; real m = m_*m_*m_; real s = s_*s_*s_; rgb[0]=+4.0767416621f * l - 3.3077115913f * m + 0.2309699292f * s; rgb[1]=-1.2684380046f * l + 2.6097574011f * m - 0.3413193965f * s; rgb[2]=-0.0041960863f * l - 0.7034186147f * m + 1.7076147010f * s; } static real _compute_max_saturation(real a, real b){ real k0, k1, k2, k3, k4, wl, wm, ws; if (-1.88170328f * a - 0.80936493f * b > 1){ k0 = +1.19086277f; k1 = +1.76576728f; k2 = +0.59662641f; k3 = +0.75515197f; k4 = +0.56771245f; wl = +4.0767416621f; wm = -3.3077115913f; ws = +0.2309699292f; } else if (1.81444104f * a - 1.19445276f * b > 1){ k0 = +0.73956515f; k1 = -0.45954404f; k2 = +0.08285427f; k3 = +0.12541070f; k4 = +0.14503204f; wl = -1.2684380046f; wm = +2.6097574011f; ws = -0.3413193965f; } else{ k0 = +1.35733652f; k1 = -0.00915799f; k2 = -1.15130210f; k3 = -0.50559606f; k4 = +0.00692167f; wl = -0.0041960863f; wm = -0.7034186147f; ws = +1.7076147010f; } real S = k0 + k1 * a + k2 * b + k3 * a * a + k4 * a * b; real k_l = +0.3963377774f * a + 0.2158037573f * b; real k_m = -0.1055613458f * a - 0.0638541728f * b; real k_s = -0.0894841775f * a - 1.2914855480f * b; { real l_ = 1.f + S * k_l; real m_ = 1.f + S * k_m; real s_ = 1.f + S * k_s; real l = l_ * l_ * l_; real m = m_ * m_ * m_; real s = s_ * s_ * s_; real l_dS = 3.f * k_l * l_ * l_; real m_dS = 3.f * k_m * m_ * m_; real s_dS = 3.f * k_s * s_ * s_; real l_dS2 = 6.f * k_l * k_l * l_; real m_dS2 = 6.f * k_m * k_m * m_; real s_dS2 = 6.f * k_s * k_s * s_; real f = wl * l + wm * m + ws * s; real f1 = wl * l_dS + wm * m_dS + ws * s_dS; real f2 = wl * l_dS2 + wm * m_dS2 + ws * s_dS2; S = S - f * f1 / (f1 * f1 - 0.5f * f * f2); } return S; } static void _find_cusp(real a, real b, real *l, real *c) { real S_cusp = _compute_max_saturation(a, b); real oklab[3]={1, S_cusp * a, S_cusp * b}; real rgb_at_max[3]; tnsOKLAB2RGB(oklab,rgb_at_max); real L_cusp = cbrt(1.f / TNS_MAX3(rgb_at_max[0], rgb_at_max[1], rgb_at_max[2])); real C_cusp = L_cusp * S_cusp; *l=L_cusp; *c=C_cusp; } static real _find_gamut_intersection(real a, real b, real L1, real C1, real L0, real cusp_L, real cusp_C) { real t; if (((L1 - L0) * cusp_C - (cusp_L - L0) * C1) <= 0.f) { t = cusp_C * L0 / (C1 * cusp_L + cusp_C * (L0 - L1)); }else{ t = cusp_C * (L0 - 1.f) / (C1 * (cusp_L - 1.f) + cusp_C * (L0 - L1)); { real dL = L1 - L0; real dC = C1; real k_l = +0.3963377774f * a + 0.2158037573f * b; real k_m = -0.1055613458f * a - 0.0638541728f * b; real k_s = -0.0894841775f * a - 1.2914855480f * b; real l_dt = dL + dC * k_l; real m_dt = dL + dC * k_m; real s_dt = dL + dC * k_s; { real L = L0 * (1.f - t) + t * L1; real C = t * C1; real l_ = L + C * k_l; real m_ = L + C * k_m; real s_ = L + C * k_s; real l = l_ * l_ * l_; real m = m_ * m_ * m_; real s = s_ * s_ * s_; real ldt = 3 * l_dt * l_ * l_; real mdt = 3 * m_dt * m_ * m_; real sdt = 3 * s_dt * s_ * s_; real ldt2 = 6 * l_dt * l_dt * l_; real mdt2 = 6 * m_dt * m_dt * m_; real sdt2 = 6 * s_dt * s_dt * s_; real r = 4.0767416621f * l - 3.3077115913f * m + 0.2309699292f * s - 1; real r1 = 4.0767416621f * ldt - 3.3077115913f * mdt + 0.2309699292f * sdt; real r2 = 4.0767416621f * ldt2 - 3.3077115913f * mdt2 + 0.2309699292f * sdt2; real u_r = r1 / (r1 * r1 - 0.5f * r * r2); real t_r = -r * u_r; real g = -1.2684380046f * l + 2.6097574011f * m - 0.3413193965f * s - 1; real g1 = -1.2684380046f * ldt + 2.6097574011f * mdt - 0.3413193965f * sdt; real g2 = -1.2684380046f * ldt2 + 2.6097574011f * mdt2 - 0.3413193965f * sdt2; real u_g = g1 / (g1 * g1 - 0.5f * g * g2); real t_g = -g * u_g; real b = -0.0041960863f * l - 0.7034186147f * m + 1.7076147010f * s - 1; real b1 = -0.0041960863f * ldt - 0.7034186147f * mdt + 1.7076147010f * sdt; real b2 = -0.0041960863f * ldt2 - 0.7034186147f * mdt2 + 1.7076147010f * sdt2; real u_b = b1 / (b1 * b1 - 0.5f * b * b2); real t_b = -b * u_b; t_r = u_r >= 0.f ? t_r : FLT_MAX; t_g = u_g >= 0.f ? t_g : FLT_MAX; t_b = u_b >= 0.f ? t_b : FLT_MAX; t += fmin(t_r, fmin(t_g, t_b)); } } } return t; } static real _toe(real x) { const real k_1 = 0.206f; const real k_2 = 0.03f; const real k_3 = (1.f + k_1) / (1.f + k_2); return 0.5f * (k_3 * x - k_1 + sqrt((k_3 * x - k_1) * (k_3 * x - k_1) + 4 * k_2 * k_3 * x)); } static real _toe_inv(real x) { const real k_1 = 0.206f; const real k_2 = 0.03f; const real k_3 = (1.f + k_1) / (1.f + k_2); return (x * x + k_1 * x) / (k_3 * (x + k_2)); } static void _to_ST(real cusp_L, real cusp_C, real* _s, real* _t) { real L = cusp_L; real C = cusp_C; *_s=C / L; *_t=C / (1 - L); } static void _get_ST_mid(real a_, real b_, real *s,real *t){ *s = 0.11516993f + 1.f / ( +7.44778970f + 4.15901240f * b_ + a_ * (-2.19557347f + 1.75198401f * b_ + a_ * (-2.13704948f - 10.02301043f * b_ + a_ * (-4.24894561f + 5.38770819f * b_ + 4.69891013f * a_ ))) ); *t = 0.11239642f + 1.f / ( +1.61320320f - 0.68124379f * b_ + a_ * (+0.40370612f + 0.90148123f * b_ + a_ * (-0.27087943f + 0.61223990f * b_ + a_ * (+0.00299215f - 0.45399568f * b_ - 0.14661872f * a_ ))) ); } static void _get_Cs(real L, real a_, real b_,real *rC_0, real *rC_mid, real *rC_max){ real cusp_L,cusp_C; _find_cusp(a_, b_,&cusp_L,&cusp_C); real C_max = _find_gamut_intersection(a_, b_, L, 1, L,cusp_L,cusp_C); real _S,_T; _to_ST(cusp_L,cusp_C,&_S, &_T); real k = C_max / fmin((L * _S), (1 - L) * _T); real C_mid;{ real _s, _t; _get_ST_mid(a_, b_,&_s,&_t); real C_a = L * _s; real C_b = (1.f - L) * _t; C_mid = 0.9f * k * sqrt(sqrt(1.f / (1.f / (C_a * C_a * C_a * C_a) + 1.f / (C_b * C_b * C_b * C_b)))); } real C_0;{ real C_a = L * 0.4f; real C_b = (1.f - L) * 0.8f; C_0 = sqrt(1.f / (1.f / (C_a * C_a) + 1.f / (C_b * C_b))); } *rC_0=C_0; *rC_mid=C_mid; *rC_max=C_max; } void tnsHCY2RGBLinear(real *hcy, real *rgb){ real h = hcy[0]; real s = hcy[1]; real l = hcy[2]; if (l >= 1.0f){ tnsVectorSet3(rgb,1,1,1); return; } else if (l <= 0.0f){ tnsVectorSet3(rgb,0,0,0); return; } real a_ = cos(2.f * TNS_PI * h); real b_ = sin(2.f * TNS_PI * h); real L = _toe_inv(l); real C_0, C_mid, C_max; _get_Cs(L, a_, b_,&C_0,&C_mid,&C_max); real mid = 0.8f; real mid_inv = 1.25f; real C, t, k_0, k_1, k_2; if (s < mid){ t = mid_inv * s; k_1 = mid * C_0; k_2 = (1.f - k_1 / C_mid); C = t * k_1 / (1.f - k_2 * t); }else{ t = (s - mid)/ (1 - mid); k_0 = C_mid; k_1 = (1.f - mid) * C_mid * C_mid * mid_inv * mid_inv / C_0; k_2 = (1.f - (k_1) / (C_max - C_mid)); C = k_0 + t * k_1 / (1.f - k_2 * t); } real okl[3]={L, C * a_, C * b_}; tnsOKLAB2RGB(okl, rgb); } void tnsRGB2HCYLinear(real *rgb, real *hcy){ real lab[3]; real lrgb[3]; lrgb[0]=rgb[0]; lrgb[1]=rgb[1]; lrgb[2]=rgb[2]; tnsRGB2OKLAB(lrgb,lab); if(lab[0]>=1.0f-1e-4){ tnsVectorSet3(hcy,0,0,1); return; } if(lab[0]<=1e-4){ tnsVectorSet3(hcy,0,0,0); return; } real C = sqrt(lab[1]*lab[1] + lab[2]*lab[2]); real a_ = (!C)?0:(lab[1] / C); real b_ = (!C)?0:(lab[2] / C); real L = lab[0]; real h = 0.5f + 0.5f * atan2(-lab[2], -lab[1]) / TNS_PI; real C_0, C_mid, C_max; _get_Cs(L, a_, b_,&C_0,&C_mid,&C_max); real mid = 0.8f; real mid_inv = 1.25f; real s; if (C < C_mid){ real k_1 = mid * C_0; real k_2 = (1.f - k_1 / C_mid); real t = C / (k_1 + k_2 * C); s = t * mid; }else{ real k_0 = C_mid; real k_1 = (1.f - mid) * C_mid * C_mid * mid_inv * mid_inv / C_0; real k_2 = (1.f - (k_1) / (C_max - C_mid)); real t = (C - k_0) / (k_1 + k_2 * (C - k_0)); s = mid + (1.f - mid) * t; } real l = _toe(L); hcy[0]=h; hcy[1]=s; hcy[2]=l; } void tnsHCY2RGB(real *hcy, real *rgb){ tnsHCY2RGBLinear(hcy,rgb); rgb[0]=_srgb_transfer_function(rgb[0]); rgb[1]=_srgb_transfer_function(rgb[1]); rgb[2]=_srgb_transfer_function(rgb[2]); } void tnsRGB2HCY(real *rgb, real *hcy){ real lrgb[3]; lrgb[0]=_srgb_transfer_function_inv(rgb[0]); lrgb[1]=_srgb_transfer_function_inv(rgb[1]); lrgb[2]=_srgb_transfer_function_inv(rgb[2]); tnsRGB2HCYLinear(lrgb,hcy); } void tnsClearAll(){ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); } void tnsClearColorv(real *rgba){ glClearColor(rgba[0], rgba[1], rgba[2], rgba[3]); } void tnsClearColor(real r, real g, real b, real a){ glClearColor(r, g, b, a); } //Assuming *result is long enough void tnsMakeIndexUInt(unsigned int *result, int num, ...){ int i; va_list list; va_start(list, num); for (i = 0; i < num; i++){ result[i] = va_arg(list, unsigned int); } va_end(list); } void tnsMakeTriangle(real *arr, real x1, real y1, real x2, real y2, real x3, real y3){ arr[0] = x1; arr[1] = y1; arr[2] = x2; arr[3] = y2; arr[4] = x3; arr[5] = y3; } void tnsMakeQuad2d(real *arr, real x1, real y1, real x2, real y2, real x3, real y3, real x4, real y4){ arr[0] = x1; arr[1] = y1; arr[2] = x2; arr[3] = y2; arr[4] = x3; arr[5] = y3; arr[6] = x4; arr[7] = y4; } void tnsMakeQuadT2d(real *arr, real x1, real y1, real x2, real y2, real x3, real y3, real x4, real y4){ arr[0] = x1; arr[1] = y1; arr[2] = x2; arr[3] = y2; arr[4] = x3; arr[5] = y3; arr[6] = x2; arr[7] = y2; arr[8] = x3; arr[9] = y3; arr[10] = x4; arr[11] = y4; } void tnsMakeQuad3d(real *arr, real x1, real y1, real z1, real x2, real y2, real z2, real x3, real y3, real z3, real x4, real y4, real z4){ arr[0] = x1; arr[1] = y1; arr[2] = z1; arr[3] = x2; arr[4] = y2; arr[5] = z2; arr[6] = x3; arr[7] = y3; arr[8] = z3; arr[9] = x4; arr[10] = y4; arr[11] = z4; } void tnsMakeQuad4d(real *arr, real x1, real y1, real z1, real w1, real x2, real y2, real z2, real w2, real x3, real y3, real z3, real w3, real x4, real y4, real z4, real w4){ arr[0] = x1; arr[1] = y1; arr[2] = z1; arr[3] = w1; arr[4] = x2; arr[5] = y2; arr[6] = z2; arr[7] = w2; arr[8] = x3; arr[9] = y3; arr[10] = z3; arr[11] = w3; arr[12] = x4; arr[13] = y4; arr[14] = z4; arr[15] = w4; } void tnsMakeCircle2d(real *arr, int slices, real ctrX, real ctrY, real r, int jump){ int i; real radstep = 2 * TNS_PI / (real)slices; real rd = 0; real x, y; for (i = 0; i < slices; i++){ x = ctrX + cos(rd) * r; y = ctrY + sin(rd) * r; int idx=2 * i * (1+jump); arr[idx] = x; arr[idx+1] = y; rd += radstep; } } void tnsMakeArc2d(real *arr, int slices, real ctrX, real ctrY, real r, real rad_begin, real rad_end){ int i; real radstep = (rad_end - rad_begin) / (real)slices; real rd = rad_begin; real x, y; for (i = 0; i <= slices; i++){ x = ctrX + cos(rd) * r; y = ctrY + sin(rd) * r; arr[2 * i] = x; arr[2 * i + 1] = y; rd += radstep; } } void tnsMakeBridgedIndex(unsigned int *result, int num, int revert, int begin){ int i; if (!revert){ for (i = 0; i < num; i++){ result[i * 2] = begin + i; result[i * 2 + 1] = begin + i + num; } }else{ for (i = 0; i < num; i++){ result[i * 2] = begin + i; result[i * 2 + 1] = begin - i + num * 2; } } } void tnsMakeRing2d(real *arr, int *index, int slices, real ctrX, real ctrY, real r1, real r2){ tnsMakeCircle2d(arr, slices, ctrX, ctrY, r1,0); tnsMakeCircle2d(&arr[slices*2], slices, ctrX, ctrY, r2,0); tnsMakeBridgedIndex(index, slices, 0, 0); index[slices*2]=0; index[slices*2+1]=slices; } void tnsMakeLinerGradient3d(real *arr, int num_points, real r0, real g0, real b0, real r1, real g1, real b1){ int i = 0; real sr = (r1 - r0) / (real)num_points, sg = (g1 - g0) / (real)num_points, sb = (b1 - b0) / (real)num_points; for (i; i < num_points; i++){ int a = 3 * i; arr[a] = r0 + sr * i; arr[a + 1] = g0 + sg * i; arr[a + 2] = b0 + sb * i; } } void tnsMakeLinerGradient4d(real *arr, int num_points, real r0, real g0, real b0, real a0, real r1, real g1, real b1, real a1){ int i = 0; real sr = (r1 - r0) / (real)num_points, sg = (g1 - g0) / (real)num_points, sb = (b1 - b0) / (real)num_points, sa = (a1 - a0) / (real)num_points; for (i; i < num_points; i++){ int a = 4 * i; arr[a] = r0 + sr * i; arr[a + 1] = g0 + sg * i; arr[a + 2] = b0 + sb * i; arr[a + 3] = a0 + sa * i; } } void tnsMakeLinerGradient3dv(real *arr, int num_points, real *rgb0, real *rgb1){ int i = 0; real sr = (rgb1[0] - rgb0[0]) / (real)num_points, sg = (rgb1[1] - rgb0[1]) / (real)num_points, sb = (rgb1[2] - rgb0[2]) / (real)num_points; for (i; i < num_points; i++){ int a = 3 * i; arr[a] = rgb0[0] + sr * i; arr[a + 1] = rgb0[1] + sg * i; arr[a + 2] = rgb0[2] + sb * i; } } void tnsMakeLinerGradient4dv(real *arr, int num_points, real *rgb0, real *rgb1){ int i = 0; real sr = (rgb1[0] - rgb0[0]) / (real)(num_points - 1), sg = (rgb1[1] - rgb0[1]) / (real)(num_points - 1), sb = (rgb1[2] - rgb0[2]) / (real)(num_points - 1), sa = (rgb1[3] - rgb0[3]) / (real)(num_points - 1); for (i; i < num_points; i++){ int a = 4 * i; arr[a] = rgb0[0] + sr * i; arr[a + 1] = rgb0[1] + sg * i; arr[a + 2] = rgb0[2] + sb * i; arr[a + 3] = rgb0[3] + sa * i; } } void tnsMakeFoucsSquare(int L, int R, int U, int B, int W){ int w = W; //int al = Len + w; real v[16]; //v[0] = L - w; v[1] = U - l; //v[2] = L - w; v[3] = U + w; //v[4] = L + l; v[4] = U + w; //v[6] = L + l; v[7] = U - w; //v[8] = L + w; v[9] = U - w; //v[10] = L + w; v[11] = U - l; //v[12] = R - l; v[13] = U + w; //v[14] = R + w; v[15] = U + w; //v[16] = R + w; v[17] = U - l; //v[18] = R - w; v[19] = U - l; //v[20] = R - w; v[21] = U - w; //v[22] = R - l; v[23] = U - w; tnsMakeQuad2d(v, L, U, R, U, R, B, L, B); tnsVertexArray2d(v, 4); tnsPackAs(GL_LINE_LOOP); tnsMakeQuad2d(&v[8], L + W, U - W, R - W, U - W, R - W, B + W, L + W, B + W); tnsVertexArray2d(&v[8], 4); tnsPackAs(GL_LINE_LOOP); } void tnsDrawFloor(int Size, int Span, int *ShowAxis){ int i = 0; int Lim = Span * 2 + 1; int Dist = Size * Span; for (i; i < Lim; i++){ if (i == Span && ShowAxis[0]) continue; tnsVertex3d(-Dist, i * Size - Dist, 0); tnsVertex3d(Dist, i * Size - Dist, 0); } for (i = 0; i < Lim; i++){ if (i == Span && ShowAxis[1]) continue; tnsVertex3d(i * Size - Dist, -Dist, 0); tnsVertex3d(i * Size - Dist, Dist, 0); } tnsPackAs(GL_LINES); if (ShowAxis[0]){ tnsColor4d(1, 0, 0, 1); tnsVertex3d(-Dist, 0, 0); tnsVertex3d(Dist, 0, 0); tnsPackAs(GL_LINES); } if (ShowAxis[1]){ tnsColor4d(0, 1, 0, 1); tnsVertex3d(0, -Dist, 0); tnsVertex3d(0, Dist, 0); tnsPackAs(GL_LINES); } if (ShowAxis[2]){ tnsColor4d(0, 0, 1, 1); tnsVertex3d(0, 0, -Dist); tnsVertex3d(0, 0, Dist); tnsPackAs(GL_LINES); } } void tnsDraw2DGrid10(real L, real R, real U, real B, real xmin, real xmax, real ymin, real ymax, real MostDenseW, real MostDenseH, real* color4, real AlphaFactor, int ShowGrid, int TextAlign){ real span; real W=R-L, H=B-U, rangeX=xmax-xmin, rangeY=ymax-ymin, dW=rangeX/W, dH=rangeY/H; real MinSpanW=fabs(MostDenseW*dW), MinSpanH=fabs(MostDenseH*dH); for(int i=0;i<20;i++){ span=1e-5*pow(10,i); if(span>MinSpanW) break; } real startx=((real)((int)(xmin/span)))*span; real x=startx; while(xMinSpanH) break; } real starty=((real)((int)(ymin/span)))*span; real y=starty; while(y