Обновление POCGL
This commit is contained in:
parent
e87ee09e77
commit
44d6d8f627
File diff suppressed because it is too large
Load diff
|
|
@ -11,26 +11,10 @@ uses System.Drawing;
|
|||
uses System;
|
||||
uses OpenGL;
|
||||
|
||||
{$apptype windows} // убираем консоль
|
||||
{$apptype windows} // убирает консоль
|
||||
|
||||
var gl: OpenGL.gl;
|
||||
|
||||
{$region Buffer}
|
||||
|
||||
function InitBuffer(sz: integer; data: IntPtr): BufferName;
|
||||
begin
|
||||
gl.CreateBuffers(1, Result);
|
||||
|
||||
gl.NamedBufferData(Result, new UIntPtr(sz), data, BufferDataUsage.STATIC_DRAW);
|
||||
|
||||
end;
|
||||
|
||||
function InitBuffer(sz: integer; data: pointer) := InitBuffer(sz, IntPtr(data));
|
||||
function InitBuffer<T>(sz: integer; var data: T) := InitBuffer(sz, @data);
|
||||
function InitBuffer<T>(data: array of T) := InitBuffer(data.Length*System.Runtime.InteropServices.Marshal.SizeOf&<T>, data[0]);
|
||||
|
||||
{$endregion Buffer}
|
||||
|
||||
{$region Shader}
|
||||
|
||||
function InitShader(fname: string; st: ShaderType): ShaderName;
|
||||
|
|
@ -39,40 +23,35 @@ begin
|
|||
|
||||
var source := ReadAllText(fname);
|
||||
|
||||
// в данной версии модуля OpenGL параметры принимающие массив строк - не поддерживаются
|
||||
// поэтому надо ручками преобразовывать управляемую строку в неуправляемую с кодировкой ANSI
|
||||
var source_strptr := System.Runtime.InteropServices.Marshal.StringToHGlobalAnsi(source);
|
||||
var source_len := source.Length;
|
||||
|
||||
gl.ShaderSource(Result, 1, source_strptr, source_len);
|
||||
|
||||
// и обязательно освобождаем память, иначе снова утечка памяти
|
||||
System.Runtime.InteropServices.Marshal.FreeHGlobal(source_strptr);
|
||||
gl.ShaderSource(Result, 1,
|
||||
new string[](source),
|
||||
new integer[](source.Length)
|
||||
);
|
||||
|
||||
gl.CompileShader(Result);
|
||||
// получаем состояние успешности компиляции
|
||||
// 1=успешно
|
||||
// 0=ошибка
|
||||
var comp_ok: integer;
|
||||
gl.GetShaderiv(Result, ShaderInfoType.COMPILE_STATUS, comp_ok);
|
||||
if comp_ok <> 1 then
|
||||
gl.GetShaderiv(Result, ShaderParameterName.COMPILE_STATUS, comp_ok);
|
||||
if comp_ok = 0 then
|
||||
begin
|
||||
|
||||
// узнаём нужную длинную строки
|
||||
var l: integer;
|
||||
gl.GetShaderiv(Result, ShaderInfoType.INFO_LOG_LENGTH, l);
|
||||
gl.GetShaderiv(Result, ShaderParameterName.INFO_LOG_LENGTH, l);
|
||||
|
||||
// выделяем достаточно памяти чтоб сохранить строку
|
||||
var ptr := System.Runtime.InteropServices.Marshal.AllocHGlobal(l);
|
||||
|
||||
// получаем строку логов
|
||||
gl.GetShaderInfoLog(Result, l, nil, ptr);
|
||||
gl.GetShaderInfoLog(Result, l, IntPtr.Zero, ptr);
|
||||
|
||||
// преобразовываем в управляемую строку
|
||||
var log := System.Runtime.InteropServices.Marshal.PtrToStringAnsi(ptr);
|
||||
writeln(log);
|
||||
Writeln(log);
|
||||
|
||||
// и опять же, в конце обязательно освобождаем памяти, чтоб не было утечек памяти
|
||||
// и в конце обязательно освобождаем памяти, чтобы не было утечек памяти
|
||||
System.Runtime.InteropServices.Marshal.FreeHGlobal(ptr);
|
||||
end;
|
||||
|
||||
|
|
@ -87,27 +66,26 @@ begin
|
|||
Result := gl.CreateProgram;
|
||||
|
||||
gl.AttachShader(Result, vertex_shader);
|
||||
if fragment_shader<>0 then gl.AttachShader(Result, fragment_shader);
|
||||
if fragment_shader<>ShaderName.Zero then gl.AttachShader(Result, fragment_shader);
|
||||
|
||||
gl.LinkProgram(Result);
|
||||
// всё то же самое что и у шейдеров
|
||||
var link_ok: integer;
|
||||
gl.GetProgramiv(Result, ProgramInfoType.LINK_STATUS, link_ok);
|
||||
if link_ok <> 1 then
|
||||
gl.GetProgramiv(Result, ProgramPropertyARB.LINK_STATUS, link_ok);
|
||||
if link_ok = 0 then
|
||||
begin
|
||||
|
||||
var l: integer;
|
||||
gl.GetProgramiv(Result, ProgramInfoType.INFO_LOG_LENGTH, l);
|
||||
gl.GetProgramiv(Result, ProgramPropertyARB.INFO_LOG_LENGTH, l);
|
||||
var ptr := System.Runtime.InteropServices.Marshal.AllocHGlobal(l);
|
||||
|
||||
gl.GetProgramInfoLog(Result, l, nil, ptr);
|
||||
gl.GetProgramInfoLog(Result, l, IntPtr.Zero, ptr);
|
||||
var log := System.Runtime.InteropServices.Marshal.PtrToStringAnsi(ptr);
|
||||
writeln(log);
|
||||
Writeln(log);
|
||||
|
||||
System.Runtime.InteropServices.Marshal.FreeHGlobal(ptr);
|
||||
end;
|
||||
|
||||
|
||||
end;
|
||||
|
||||
{$endregion Program}
|
||||
|
|
@ -133,38 +111,60 @@ begin
|
|||
|
||||
{$region Настройка глобальных параметров OpenGL}
|
||||
|
||||
// при создании экземпляра OpenGL.gl инициализируются некоторые функции
|
||||
// это необходимо для всех функций из OpenGL1.2 и выше, потому что они локальные для контекста OpenGL
|
||||
// При создании экземпляра OpenGL.gl инициализируются некоторые функции
|
||||
// Это необходимо для всех функций из OpenGL1.2 и выше, потому что они локальны для контекста OpenGL
|
||||
gl := new OpenGL.gl;
|
||||
|
||||
{$endregion Настройка глобальных параметров OpenGL}
|
||||
|
||||
{$region Инициализация переменных}
|
||||
|
||||
var vertex_pos_buffer := InitBuffer(ArrGen(3, i->
|
||||
begin
|
||||
var rot := i * Pi * 2 / 3;
|
||||
|
||||
Result := new Vec2f(
|
||||
Sin(rot),
|
||||
Cos(rot) + dy
|
||||
);
|
||||
|
||||
end));
|
||||
var vertex_clr_buffer := InitBuffer(new Vec3f[](
|
||||
new Vec3f(1,0,0),
|
||||
new Vec3f(0,1,0),
|
||||
new Vec3f(0,0,1)
|
||||
));
|
||||
var vertex_pos_buffer: BufferName;
|
||||
gl.CreateBuffers(1, vertex_pos_buffer);
|
||||
gl.NamedBufferData(
|
||||
vertex_pos_buffer,
|
||||
new IntPtr(3*sizeof(Vec2f)),
|
||||
ArrGen(3, i->
|
||||
begin
|
||||
var rot := i * Pi * 2 / 3;
|
||||
|
||||
Result := new Vec2f(
|
||||
Sin(rot),
|
||||
Cos(rot) + dy
|
||||
);
|
||||
|
||||
end),
|
||||
VertexBufferObjectUsage.STATIC_DRAW
|
||||
);
|
||||
|
||||
var element_buffer := InitBuffer(new byte[](
|
||||
0,1,2
|
||||
));
|
||||
var vertex_clr_buffer: BufferName;
|
||||
gl.CreateBuffers(1, vertex_clr_buffer);
|
||||
gl.NamedBufferData(
|
||||
vertex_clr_buffer,
|
||||
new IntPtr(3*sizeof(Vec3f)),
|
||||
new Vec3f[](
|
||||
new Vec3f(1,0,0),
|
||||
new Vec3f(0,1,0),
|
||||
new Vec3f(0,0,1)
|
||||
),
|
||||
VertexBufferObjectUsage.STATIC_DRAW
|
||||
);
|
||||
|
||||
var element_buffer: BufferName;
|
||||
gl.CreateBuffers(1, element_buffer);
|
||||
gl.NamedBufferData(
|
||||
element_buffer,
|
||||
new IntPtr(3*sizeof(byte)),
|
||||
new byte[](
|
||||
0,1,2
|
||||
),
|
||||
VertexBufferObjectUsage.STATIC_DRAW
|
||||
);
|
||||
|
||||
var vertex_shader := InitShader('Rot Triangle 1.vertex.glsl', ShaderType.VERTEX_SHADER);
|
||||
// var fragment_shader := InitShader('fragment.glsl', ShaderType.FRAGMENT_SHADER);
|
||||
|
||||
var sprog := InitProgram(vertex_shader, 0 {fragment_shader});
|
||||
var sprog := InitProgram(vertex_shader, ShaderName.Zero {fragment_shader});
|
||||
|
||||
var uniform_rot_k := gl.GetUniformLocation(sprog, 'rot_k');
|
||||
|
||||
|
|
@ -179,7 +179,7 @@ begin
|
|||
while true do
|
||||
begin
|
||||
// очищаем окно в начале перерисовки
|
||||
gl.Clear(BufferTypeFlags.COLOR_BUFFER_BIT);
|
||||
gl.Clear(ClearBufferMask.COLOR_BUFFER_BIT);
|
||||
|
||||
|
||||
|
||||
|
|
@ -187,34 +187,34 @@ begin
|
|||
|
||||
gl.Uniform1f(uniform_rot_k, Cos( t.Elapsed.Ticks * 0.0000002 ) );
|
||||
|
||||
gl.BindBuffer(BufferBindType.ARRAY_BUFFER, vertex_pos_buffer);
|
||||
gl.BindBuffer(BufferTargetARB.ARRAY_BUFFER, vertex_pos_buffer);
|
||||
gl.VertexAttribPointer(
|
||||
attribute_position,
|
||||
2,
|
||||
DataType.FLOAT,
|
||||
VertexAttribPointerType.FLOAT,
|
||||
false,
|
||||
8,
|
||||
nil
|
||||
IntPtr.Zero
|
||||
);
|
||||
gl.EnableVertexAttribArray(attribute_position);
|
||||
|
||||
gl.BindBuffer(BufferBindType.ARRAY_BUFFER, vertex_clr_buffer);
|
||||
gl.BindBuffer(BufferTargetARB.ARRAY_BUFFER, vertex_clr_buffer);
|
||||
gl.VertexAttribPointer(
|
||||
attribute_color,
|
||||
3,
|
||||
DataType.FLOAT,
|
||||
VertexAttribPointerType.FLOAT,
|
||||
false,
|
||||
12,
|
||||
nil
|
||||
IntPtr.Zero
|
||||
);
|
||||
gl.EnableVertexAttribArray(attribute_color);
|
||||
|
||||
gl.BindBuffer(BufferBindType.ELEMENT_ARRAY_BUFFER, element_buffer);
|
||||
gl.BindBuffer(BufferTargetARB.ELEMENT_ARRAY_BUFFER, element_buffer);
|
||||
gl.DrawElements(
|
||||
PrimitiveType.TRIANGLES,
|
||||
3,
|
||||
DataType.UNSIGNED_BYTE,
|
||||
pointer(nil)
|
||||
DrawElementsType.UNSIGNED_BYTE,
|
||||
IntPtr.Zero
|
||||
);
|
||||
|
||||
gl.DisableVertexAttribArray(attribute_position);
|
||||
|
|
@ -225,7 +225,7 @@ begin
|
|||
// получаем тип последней ошибки
|
||||
var err := gl.GetError;
|
||||
// и если ошибка есть - выводим её
|
||||
if err.val<>ErrorCode.NO_ERROR then writeln(err);
|
||||
if err<>ErrorCode.NO_ERROR then Writeln(err);
|
||||
|
||||
gl.Finish;
|
||||
// EndFrame меняет местами буферы и ждёт vsync
|
||||
File diff suppressed because it is too large
Load diff
|
|
@ -9,6 +9,7 @@
|
|||
body {
|
||||
background-color: #F0F0F0;
|
||||
margin: 0px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.page-base {
|
||||
|
|
@ -86,9 +87,14 @@ body {
|
|||
margin-left: 8px;
|
||||
}
|
||||
.spoiler-wrap {
|
||||
border-left: thin solid;
|
||||
border: solid;
|
||||
border-width: 0px;
|
||||
padding-left: 2px;
|
||||
}
|
||||
.spoiler-name {
|
||||
border: solid;
|
||||
border-width: 0px;
|
||||
}
|
||||
|
||||
.code-block {
|
||||
display: inline-block;
|
||||
|
|
@ -101,6 +107,19 @@ body {
|
|||
|
||||
margin: 0;
|
||||
|
||||
position: relative;
|
||||
}
|
||||
.code-block-copier {
|
||||
cursor: pointer;
|
||||
padding: 2px;
|
||||
|
||||
position: absolute;
|
||||
top: 0;
|
||||
|
||||
border: thin solid;
|
||||
border-radius: 3.7px 0px 3.7px 3.7px;
|
||||
box-shadow: -2px 2px 3px #0000004a;
|
||||
background: linear-gradient(0deg, #f0f0f0, white);
|
||||
}
|
||||
.inline-code {
|
||||
background: #F0F0F0;
|
||||
|
|
@ -142,6 +161,10 @@ const pointed_name_color = "#d1faff";
|
|||
|
||||
var localStorageKey = "";
|
||||
|
||||
const get_style = (el)=>el.currentStyle || window.getComputedStyle(el);
|
||||
|
||||
var spl_resize_event = [];
|
||||
|
||||
/* ============================== *\
|
||||
page load
|
||||
\* ============================== */
|
||||
|
|
@ -368,20 +391,23 @@ const on_end_folder = ()=>{
|
|||
\* ============================== */
|
||||
|
||||
var selected_page = null;
|
||||
var scroll_by_page = {};
|
||||
const is_selected = (name_span)=>(!selected_page || selected_page.name_span!==name_span);
|
||||
const select_page = (new_page)=>{
|
||||
if (selected_page == new_page) return;
|
||||
document.location.hash = new_page.tree_obj.path;
|
||||
fix_element(new_page);
|
||||
|
||||
if (selected_page) {
|
||||
let container = document.getElementById("page-display-container");
|
||||
|
||||
if (selected_page)
|
||||
{
|
||||
scroll_by_page[selected_page.tree_obj.path] = container.scrollTop;
|
||||
selected_page.hidden = true;
|
||||
let name_span = selected_page.name_span;
|
||||
if (name_span) name_span.style.backgroundColor = "inherit";
|
||||
}
|
||||
|
||||
document.getElementById("page-display-container-body").scrollTop = 0;
|
||||
|
||||
selected_page = new_page;
|
||||
if (selected_page)
|
||||
{
|
||||
|
|
@ -396,8 +422,8 @@ const select_page = (new_page)=>{
|
|||
tree_obj = tree_obj.root;
|
||||
}
|
||||
|
||||
container.scrollTop = scroll_by_page[selected_page.tree_obj.path] || 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
const make_smart_link = (lnk, page)=>{
|
||||
|
|
@ -441,8 +467,18 @@ const fix_links = (page)=>{
|
|||
|
||||
const code_words_color = {
|
||||
"pas": {
|
||||
"keyword": ["begin", "end", "var", "uses", "as", "new", "try", "except", "on", "do", "const", "procedure", "function", "lock", "type", "class", "sizeof"],
|
||||
"build-in": ["nil", "integer", "string", "object", "byte"],
|
||||
"keyword": [
|
||||
"begin","end", "var", "uses", "as", "new", "try", "except", "on", "do", "const",
|
||||
"procedure", "function", "lock", "type", "class","record", "sizeof","typeof", "external",
|
||||
"static", "array", "where", "or","and", "public","private", "property","constructor", "default",
|
||||
"of", "if","then","else", "div","mod", "extensionmethod", "while",
|
||||
],
|
||||
"build-in": [
|
||||
"nil", "self", "true", "false",
|
||||
"string","char", "object", "pointer", "single","real",
|
||||
"shortint", "smallint", "integer", "int64",
|
||||
"byte", "word", "longword", "cardinal", "uint64",
|
||||
],
|
||||
"red": ["ToDo"],
|
||||
},
|
||||
"cl-c": {
|
||||
|
|
@ -465,19 +501,21 @@ const fix_element = (page)=>{
|
|||
let wrap = document.createElement('p');
|
||||
wrap.className = "spoiler-wrap";
|
||||
wrap.update = ()=>{
|
||||
wrap.state_span.innerHTML = String.fromCharCode( spoiler.hidden ? 0x25BA : 0x25BC );
|
||||
wrap.style.border = spoiler.hidden ? "none" : null;
|
||||
wrap.style.marginLeft = spoiler.hidden ? "1px" : null;
|
||||
wrap.state_span.innerHTML = String.fromCharCode( spoiler.hidden ? 0x25BA : 0x25BC );
|
||||
wrap.style.borderLeftWidth = spoiler.hidden ? 0 : 1;
|
||||
wrap.name_span.style.borderBottomWidth = spoiler.hidden ? 1 : 0;
|
||||
wrap.style.marginLeft = spoiler.hidden ? 1 : 0;
|
||||
}
|
||||
|
||||
wrap.state_span = document.createElement("span");
|
||||
wrap.update();
|
||||
wrap.append(wrap.state_span);
|
||||
|
||||
wrap.name_span = document.createElement("span");
|
||||
wrap.name_span.className = "spoiler-name";
|
||||
wrap.name_span.innerHTML = spoiler.getAttribute("summary");
|
||||
wrap.append(wrap.name_span);
|
||||
|
||||
wrap.update();
|
||||
wrap.reverse_state = ()=>{
|
||||
spoiler.hidden = !spoiler.hidden;
|
||||
wrap.update();
|
||||
|
|
@ -497,6 +535,8 @@ const fix_element = (page)=>{
|
|||
{
|
||||
let w_to_regex = (w)=>`(?<!\\w)${w}(?!\\w)`;
|
||||
|
||||
let code_html = code.innerHTML;
|
||||
|
||||
// Автоопределение языка кода
|
||||
if (!code.className)
|
||||
{
|
||||
|
|
@ -509,7 +549,7 @@ const fix_element = (page)=>{
|
|||
for (let wordt in code_words_color[lang_name])
|
||||
for (let w of code_words_color[lang_name][wordt])
|
||||
{
|
||||
var m = code.innerHTML.match(new RegExp( w_to_regex(w), "gi" ));
|
||||
var m = code_html.match(new RegExp( w_to_regex(w), "gi" ));
|
||||
if (m) c += m.length;
|
||||
}
|
||||
|
||||
|
|
@ -534,13 +574,13 @@ const fix_element = (page)=>{
|
|||
let curr_cw = code_words_color[lang];
|
||||
if (!curr_cw) curr_cw = code_words_color["default"];
|
||||
for (let wordt in curr_cw)
|
||||
code.innerHTML = code.innerHTML.replace(
|
||||
code_html = code_html.replace(
|
||||
new RegExp(curr_cw[wordt].map(w_to_regex).join('|'),"gi"),
|
||||
w=> `<span class="code-${wordt}">${w}</span>`
|
||||
);
|
||||
}
|
||||
|
||||
// Подсветка скобок
|
||||
// Выделение скобок
|
||||
{
|
||||
var br_types = {
|
||||
op: ["(", "[", "{", "<", "'"],
|
||||
|
|
@ -548,11 +588,27 @@ const fix_element = (page)=>{
|
|||
}
|
||||
for (let op in br_types)
|
||||
for (let i=0; i<br_types[op].length; i++)
|
||||
code.innerHTML = code.innerHTML.replace(
|
||||
code_html = code_html.replace(
|
||||
new RegExp('\\'+br_types[op][i], "g"),
|
||||
`<span class=bracket ${ op=="op" ? "op=true" : "" } bt=${i}>${br_types[op][i]}</span>`
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
// Выделение первой строки
|
||||
if (code.parentElement.tagName == "PRE")
|
||||
{
|
||||
let ind = code_html.indexOf('\n');
|
||||
if (ind != code_html.length-1)
|
||||
code_html = `<span class="code-first-line">${code_html.slice(0,ind)}</span>${code_html.slice(ind)}`;
|
||||
}
|
||||
|
||||
code.innerHTML = code_html;
|
||||
code.firstLine = code.children[0];
|
||||
if (code.firstLine && code.firstLine.className != "code-first-line") delete code.firstLine;
|
||||
|
||||
// Подсветка скобок
|
||||
{
|
||||
let br_st = [];
|
||||
for (let obj2 of code.getElementsByClassName("bracket"))
|
||||
{
|
||||
|
|
@ -615,6 +671,80 @@ const fix_element = (page)=>{
|
|||
|
||||
}
|
||||
|
||||
page.style.visibility = "hidden";
|
||||
page.hidden = false;
|
||||
|
||||
for (let code of page.getElementsByTagName('code'))
|
||||
{
|
||||
if (code.firstLine)
|
||||
{
|
||||
let pre = code.parentElement;
|
||||
|
||||
let copy_button = document.createElement('div');
|
||||
copy_button.className = "code-block-copier";
|
||||
copy_button.innerText = "Копировать";
|
||||
copy_button.style.visibility = "hidden";
|
||||
pre.append(copy_button);
|
||||
|
||||
copy_button.addEventListener("click", ()=>{
|
||||
|
||||
if (document.selection) { // IE
|
||||
var range = document.body.createTextRange();
|
||||
range.moveToElementText(code);
|
||||
range.select();
|
||||
} else if (window.getSelection) { // other browsers
|
||||
var range = document.createRange();
|
||||
range.selectNode(code);
|
||||
window.getSelection().removeAllRanges();
|
||||
window.getSelection().addRange(range);
|
||||
}
|
||||
|
||||
var text = code.innerText;
|
||||
navigator.clipboard.writeText(text.substring(0,text.length-1));
|
||||
});
|
||||
|
||||
copy_button.reset_right = ()=>{
|
||||
pre_st = get_style(pre);
|
||||
let container = document.getElementById("page-display-container");
|
||||
let x = pre.getBoundingClientRect().right - (container.getBoundingClientRect().left+container.clientWidth);
|
||||
if (x<0) x = 0; else
|
||||
{
|
||||
let max_x = pre.offsetWidth - copy_button.offsetWidth;
|
||||
if (x>max_x) x = max_x;
|
||||
}
|
||||
copy_button.style.right = x;
|
||||
};
|
||||
let try_reset_right = ()=>{
|
||||
if (!copy_button.hidden)
|
||||
copy_button.reset_right();
|
||||
};
|
||||
spl_resize_event.push(try_reset_right);
|
||||
window.addEventListener("resize", try_reset_right);
|
||||
|
||||
pre.addEventListener("mouseenter", ()=>{
|
||||
copy_button.hidden = false;
|
||||
copy_button.reset_right();
|
||||
});
|
||||
pre.addEventListener("mouseleave", ()=>copy_button.hidden = true);
|
||||
|
||||
copy_button.addEventListener("mousedown", ()=>copy_button.style.background = "linear-gradient(180deg, rgb(240, 240, 240), white)");
|
||||
copy_button.addEventListener("mouseup", ()=>copy_button.style.background = "linear-gradient( 0deg, rgb(240, 240, 240), white)");
|
||||
copy_button.addEventListener("mouseleave", ()=>copy_button.style.background = "linear-gradient( 0deg, rgb(240, 240, 240), white)");
|
||||
|
||||
pre.style.minWidth =
|
||||
code.firstLine.offsetWidth +
|
||||
copy_button.offsetWidth +
|
||||
0
|
||||
;
|
||||
|
||||
copy_button.hidden = true;
|
||||
copy_button.style.visibility = null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
page.hidden = true;
|
||||
page.style.visibility = null;
|
||||
}
|
||||
|
||||
/* ============================== *\
|
||||
|
|
@ -623,11 +753,21 @@ const fix_element = (page)=>{
|
|||
|
||||
{
|
||||
if (document.location.hash)
|
||||
define_broken_lnk(
|
||||
decodeURIComponent(document.location.hash.substr(1)),
|
||||
{
|
||||
let get_hash = ()=>decodeURIComponent(document.location.hash.substr(1));
|
||||
let define_hash_lnk = ()=>define_broken_lnk(
|
||||
get_hash(),
|
||||
"document.location.hash",
|
||||
page=>select_page(page)
|
||||
);
|
||||
define_hash_lnk();
|
||||
window.addEventListener("hashchange", ()=>{
|
||||
let hash_page = page_by_path[get_hash()];
|
||||
if (hash_page)
|
||||
select_page(hash_page); else
|
||||
define_hash_lnk();
|
||||
});
|
||||
}
|
||||
|
||||
let page_select = document.getElementById("page-select");
|
||||
let page_display = document.getElementById("page-display");
|
||||
|
|
@ -640,8 +780,8 @@ const fix_element = (page)=>{
|
|||
{
|
||||
let par = cont.parentElement;
|
||||
par.update_cont = (w)=>{
|
||||
cont.style.width = w-15 + "px";
|
||||
cont.style.height = wh-15 + "px";
|
||||
cont.style.width = w-15;
|
||||
cont.style.height = wh-15;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -666,10 +806,13 @@ const fix_element = (page)=>{
|
|||
|
||||
page_select.update_cont(spl_X);
|
||||
page_display.update_cont(w2);
|
||||
|
||||
for (let handler of spl_resize_event)
|
||||
handler();
|
||||
}
|
||||
reset_spl();
|
||||
|
||||
window.onresize = ()=>reset_spl();
|
||||
window.addEventListener("resize", ()=>reset_spl());
|
||||
|
||||
splitter.addEventListener("dblclick", ()=>{
|
||||
let w = 0;
|
||||
|
|
@ -679,7 +822,7 @@ const fix_element = (page)=>{
|
|||
if (n.clientWidth>w) w = n.clientWidth;
|
||||
|
||||
let get_margin = (el)=>{
|
||||
let style = el.currentStyle || window.getComputedStyle(el);
|
||||
let style = get_style(el);
|
||||
return parseFloat(style.marginLeft) + parseFloat(style.marginRight);
|
||||
}
|
||||
|
||||
|
|
@ -726,7 +869,7 @@ window.onload = ()=>{
|
|||
Вместо этого надо использовать операции с очередями (например, сложение и умножение очередей)</p>
|
||||
<p>Справка модуля <code>OpenCL</code> отсутствует. Вместо неё смотрите:</p>
|
||||
<ul>
|
||||
<li><a href="../%D0%93%D0%B0%D0%B9%D0%B4%20%D0%BF%D0%BE%20%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D1%8E%20OpenCL%20%D0%B8%20OpenGL.html">Общий гайд по использованию модулей <code>OpenCL</code> и <code>OpenGL</code></a></li>
|
||||
<li><a href="%D0%93%D0%B0%D0%B9%D0%B4%20%D0%BF%D0%BE%20%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D1%8E%20OpenGL%20%D0%B8%20OpenCL.html">Общий гайд по использованию модулей <code>OpenGL</code> и <code>OpenCL</code></a></li>
|
||||
<li><a href="https://www.khronos.org/registry/OpenCL/">Контейнер справок библиотеки <code>OpenCL</code>, на которой основан модуль <code>OpenCL</code></a></li>
|
||||
</ul>
|
||||
<p>Если в справке или модуле найдена ошибка, или чего-либо не хватает - пишите в <a href="https://github.com/SunSerega/POCGL/issues">issue</a>.</p>
|
||||
|
|
@ -734,26 +877,26 @@ window.onload = ()=>{
|
|||
<script>on_page_added(document.getElementById("page-1"))</script>
|
||||
<div id="page-2" page_name="Термины, которые часто путают новички" hidden=true>
|
||||
<ul>
|
||||
<li><p>CPU — Центральное Процессорное Устройство (процессор)</p>
|
||||
<li><p>CPU — Центральное Процессорное Устройство (процессор);</p>
|
||||
</li>
|
||||
<li><p>GPU — Графическое Процессорное Устройство (видеокарта)</p>
|
||||
<li><p>GPU — Графическое Процессорное Устройство (видеокарта);</p>
|
||||
</li>
|
||||
<li><p>Команда — запрос на выполнение чего-либо. К примеру:</p>
|
||||
<ul>
|
||||
<li>Запрос на запуск программы на GPU</li>
|
||||
<li>Запрос на начало чтения данных из памяти GPU в оперативную память</li>
|
||||
<li>Запрос на запуск программы на GPU;</li>
|
||||
<li>Запрос на начало чтения данных из памяти GPU в оперативную память;</li>
|
||||
</ul>
|
||||
<p><strong>Называть процедуры и функции командами ошибочно!</strong></p>
|
||||
</li>
|
||||
<li><p>Подпрограмма — процедура или функция</p>
|
||||
<li><p>Подпрограмма — процедура или функция;</p>
|
||||
</li>
|
||||
<li><p>Метод — особая подпрограмма, вызываемая через экземпляр</p>
|
||||
<li><p>Метод — особая подпрограмма, вызываемая через экземпляр:</p>
|
||||
<ul>
|
||||
<li>К примеру, метод <code>Context.SyncInvoke</code> выглядит в коде как <code>cont.SyncInvoke(...)</code>, где <code>cont</code> — переменная типа <code>Context</code></li>
|
||||
<li>К примеру, метод <code>Context.SyncInvoke</code> выглядит в коде как <code>cont.SyncInvoke(...)</code>, где <code>cont</code> — переменная типа <code>Context</code>;</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
<p>Остальные непонятные термины можно найти в справке <code>PascalABC.NET</code> или в интернете</p>
|
||||
<p>Остальные непонятные термины можно найти в справке <code>PascalABC.NET</code> или в интернете.</p>
|
||||
</div>
|
||||
<script>on_page_added(document.getElementById("page-2"))</script>
|
||||
<script>on_end_folder()</script>
|
||||
|
|
@ -771,7 +914,7 @@ window.onload = ()=>{
|
|||
Если <code>Context.Default = nil</code> - переустановите графические драйверы.</p>
|
||||
<hr />
|
||||
<p><code>Context.Default</code> можно перезаписывать.</p>
|
||||
<p>Используйте эту возможность только если во всей программе нужет общий контекст, но не стандартный.</p>
|
||||
<p>Используйте эту возможность только если во всей программе нужен общий контекст, но не стандартный.</p>
|
||||
<p>Частая перезапись <code>Context.Default</code> может привести к созданию сложно-ловимых багов в ваших программах.</p>
|
||||
<hr />
|
||||
<p>Операции, у которых невозможно указать контекст, всегда используют <code>Context.Default</code>.</p>
|
||||
|
|
@ -928,6 +1071,7 @@ if cq=nil then
|
|||
Writeln('Очередь не константная') else
|
||||
Writeln($'Очередь была создана из значения {cq.Val}');
|
||||
</code></pre>
|
||||
<hr />
|
||||
<p><code>CommandQueueBase</code> также можно создать из значения, но для этого тип значения должен быть <code>Object</code>:</p>
|
||||
<pre><code>var q: CommandQueueBase := 5 as object;
|
||||
</code></pre>
|
||||
|
|
@ -943,14 +1087,14 @@ if cq=nil then
|
|||
<p>Иногда между командами для GPU надо вставить выполнение обычного кода на CPU.
|
||||
А разрывать для этого очередь на две части - плохо, потому что
|
||||
одна целая очередь всегда выполнится быстрее двух её частей.</p>
|
||||
<p>Для таких случае существуют глобальные подпрограммы HFQ и HPQ:</p>
|
||||
<p>Для таких случае существуют глобальные подпрограммы <code>HFQ</code> и <code>HPQ</code>:</p>
|
||||
<p>HFQ — Host Function Queue<br />
|
||||
HPQ — Host Procedure Queue<br />
|
||||
(Хост в контексте OpenCL - это CPU, потому что с него посылаются команды для GPU)</p>
|
||||
<p>Они возвращают очередь, выполняющую код (функцию/процедуру соотвественно) на CPU.<br />
|
||||
Подробнее уже описано
|
||||
<a path="../Возвращаемое значение очередей/">
|
||||
на предыдущей странице
|
||||
на странице выше
|
||||
</a>
|
||||
.</p>
|
||||
</div>
|
||||
|
|
@ -969,7 +1113,8 @@ begin
|
|||
|
||||
var q1 := HPQ(()->
|
||||
begin
|
||||
// lock необходим чтобы при параллельном выполнении два потока не пытались использовать вывод одновременно. Иначе выведет кашу
|
||||
// lock необходим чтобы при параллельном выполнении два потока
|
||||
// не пытались использовать вывод одновременно. Иначе выведет кашу
|
||||
lock output do Writeln('Очередь 1 начала выполняться');
|
||||
Sleep(500);
|
||||
lock output do Writeln('Очередь 1 закончила выполняться');
|
||||
|
|
@ -1013,11 +1158,11 @@ begin
|
|||
// А точнее их перегрузку, первый параметр которой - функция преобразования
|
||||
Context.Default.SyncInvoke(
|
||||
CombineSyncQueue(
|
||||
results->results.JoinIntoString, // функция преобразования
|
||||
results->results.JoinToString, // функция преобразования
|
||||
q1, q2
|
||||
)
|
||||
).Println;
|
||||
// Теперь выводит строку "1 2". Это то же самое, что вернёт "Arr(1,2).JoinIntoString"
|
||||
// Теперь выводит строку "1 2". Это то же самое, что вернёт "Arr(1,2).JoinToString"
|
||||
|
||||
end.
|
||||
</code></pre>
|
||||
|
|
@ -1053,7 +1198,8 @@ Context.Default.SyncInvoke( Q4.Cast&<t2> );
|
|||
// Можно, потому что t2 наследует от t1
|
||||
Context.Default.SyncInvoke( Q5.Cast&<t1> );
|
||||
</code></pre>
|
||||
<p>Ну а если эти ограничения не подходят - остаётся только <code>.ThenConvert</code>. Он позволяет указать любой алгоритм преобразования, но и требует бОльшей производительности:</p>
|
||||
<p>Ну а если эти ограничения не подходят - остаётся только <code>.ThenConvert</code>.
|
||||
Он позволяет указать любой алгоритм преобразования, но работает медленнее:</p>
|
||||
<pre><code>uses OpenCLABC;
|
||||
|
||||
begin
|
||||
|
|
@ -1183,13 +1329,13 @@ var q := b.NewQueue
|
|||
</code></pre>
|
||||
<p>(вообще callback AddProc'а принимает исходный буфер/kernel параметром, что делает его более похожим на <code>.ThenConvert</code>, чем <code>HPQ</code>)</p>
|
||||
<p>Эти методы не имеют незаменимых применений, но позволяют сделать код значительно читабельнее.</p>
|
||||
<p>Кроме того, будьте осторожны, защиты от дурака для такого случая - отсутствует:</p>
|
||||
<p>Кроме того, будьте осторожны, защита от дурака для такого случая - отсутствует:</p>
|
||||
<pre><code>var q := b.NewQueue;
|
||||
q.AddQueue(q);
|
||||
</code></pre>
|
||||
<p>Все <code>.Add*</code> методы добавляют команды в существующую очередь, а не создают новую.
|
||||
Поэтому очередь, созданная предыдущим кодом при попытке выполнения начнёт циклически запускать саму себя.
|
||||
Но это вызовет скорее не зависание, а переполнение стека (что, в целом, не лучше).</p>
|
||||
Но это вызовет скорее не зависание, а переполнение стека (что, впрочем, не лучше).</p>
|
||||
</div>
|
||||
<script>on_page_added(document.getElementById("page-14"))</script>
|
||||
<div id="page-15" page_name="Из ожидания очередей" hidden=true>
|
||||
|
|
@ -1299,7 +1445,7 @@ begin
|
|||
|
||||
var t1 := Context.Default.BeginInvoke(
|
||||
WaitFor(Q1) +
|
||||
WaitFor(Q1) // второго запуска Q1 никогда не произойдёт, поэтому это зависнет
|
||||
WaitFor(Q1) // второй запуск Q1 никогда не произойдёт, поэтому это зависнет
|
||||
);
|
||||
Context.Default.BeginInvoke(Q1);
|
||||
|
||||
|
|
@ -1307,7 +1453,7 @@ begin
|
|||
end.
|
||||
</code></pre>
|
||||
<hr />
|
||||
<p>Cчётчик создаётся для каждой пары [ожидаемой очереди] и [вызова <code>Context.BeginInvoke</code>] для ожидающей очереди.
|
||||
<p>Cчётчик создаётся для каждой пары [ожидаемой очереди] и [вызова <code>Context.BeginInvoke</code> с ожидающей очередью].
|
||||
То есть это тоже сработает:</p>
|
||||
<pre><code>uses OpenCLABC;
|
||||
|
||||
|
|
@ -1363,15 +1509,15 @@ end.
|
|||
</code></pre>
|
||||
<hr />
|
||||
<p>И последнее что надо знать - <code>Wait-Any</code> очередь хоть и ожидает выполнения любой одной очереди из списка,
|
||||
но отнимает 1 от счётчиков всех ожидаемых очередей из того списка.</p>
|
||||
но отнимает 1 от счётчиков всех ожидаемых очередей из своего списка.</p>
|
||||
</div>
|
||||
<script>on_page_added(document.getElementById("page-15"))</script>
|
||||
<div id="page-16" page_name="Не создавая явно" hidden=true>
|
||||
<p>Передавать команды по одной, когда их несколько - ужасно медленно!<br />
|
||||
Но нередко бывает так, что команда всего одна. Или для отладки надо одноразово выполнить одну команду.</p>
|
||||
<p>Для таких случаев можно создавать очередь неявно:<br />
|
||||
У каждого метода очереди, создаваемой с <code>.NewQueue</code> есть дублирующий метод в оригинальном объекте.
|
||||
Такие методы сами создают новую очередь, добавляют в неё одну соответствующую команду и выполняют полученную очередь в <code>Context.Default.SyncInvoke(...)</code>.</p>
|
||||
У каждого <code>.Add*</code> метода есть дублирующий метод в оригинальном объекте. Такие методы сами создают
|
||||
новую очередь, добавляют в неё одну соответствующую команду и выполняют полученную очередь в <code>Context.Default.SyncInvoke(...)</code>.</p>
|
||||
<p>Обычный код с очередями:</p>
|
||||
<pre><code>uses OpenCLABC;
|
||||
|
||||
|
|
@ -1422,9 +1568,9 @@ begin
|
|||
|
||||
end.
|
||||
</code></pre>
|
||||
<p>Кроме того, у типа <code>Buffer</code> есть дополнительные методы <code>Buffer.Get...</code>.
|
||||
<p>Кроме того, у типа <code>Buffer</code> есть дополнительные методы <code>Buffer.Get*</code>.
|
||||
Соответствующих методов у очередей — нет (<code>ToDo</code> возможно, в будущем появятся).</p>
|
||||
<p>Методы <code>.Get...</code> создают новый объект типа записи, массива или выделяют область неуправляемой памяти,
|
||||
<p>Методы <code>.Get*</code> создают новый объект типа записи, массива или выделяют область неуправляемой памяти,
|
||||
читают в полученный объект содержимое буфера и возвращают этот объект.
|
||||
Они также используют неявную очередь (для чтения буфера).</p>
|
||||
</div>
|
||||
|
|
@ -1495,8 +1641,8 @@ begin
|
|||
|
||||
end.
|
||||
</code></pre>
|
||||
<p>Все очереди-параметры начинают выполнятся сразу при вызове метода <code>Context.BeginInvoke</code>, не ожидая других очередей.</p>
|
||||
<p>Обычно очереди-параметры используются при вызове kernel'а,
|
||||
<p>Все вложенные очереди начинают выполнятся сразу при вызове метода <code>Context.BeginInvoke</code>, не ожидая других очередей.</p>
|
||||
<p>Обычно вложенные очереди используются при вызове kernel'а,
|
||||
когда надо записать что-то в буфер прямо перед вызовом kernel'а.</p>
|
||||
</div>
|
||||
<script>on_start_folder("Вложенные очереди", document.getElementById("page-18"))</script>
|
||||
|
|
@ -1514,9 +1660,9 @@ end.
|
|||
<p>Когда на GPU выделяется память - она <strong>НЕ</strong> очищается, а значит содержит мусорные данные.</p>
|
||||
<p>Если метод <code>Buffer.Init</code> не был вызван до первой операции чтения/записи - он будет вызван автоматически.
|
||||
В таком случае в качестве контекста в котором выделяется память берётся тот,
|
||||
для которого вызвали <code>.BeginInvoke</code>, который запустил команду чтения/записи буфера.</p>
|
||||
на котором вызвали <code>.BeginInvoke</code>, который запустил команду чтения/записи буфера.</p>
|
||||
<p>Память на GPU можно моментально освободить, вызвав метод <code>Buffer.Dispose</code>.
|
||||
Но если снова использовать буфер, у которого освободили память - память опять выделится.</p>
|
||||
Но если снова использовать буфер, у которого освободили память - память заново выделится.</p>
|
||||
<p>Если сборщик мусора удаляет объект типа <code>Buffer</code> - <code>.Dispose</code> вызывается автоматически.</p>
|
||||
</div>
|
||||
<script>on_start_folder("Буфер (Buffer)", document.getElementById("page-19"))</script>
|
||||
|
|
@ -1622,17 +1768,19 @@ begin
|
|||
|
||||
var A := new Buffer( 10 * sizeof(integer) ); // буфер на 10 чисел типа "integer"
|
||||
|
||||
// 'TEST' - имя подпрограммы-кёрнела из .cl файла. Регистр важен!
|
||||
// 'TEST' - имя подпрограммы-kernel'а из .cl файла. Регистр важен!
|
||||
var kernel := code['TEST'];
|
||||
|
||||
kernel.Exec1(10, // используем 10 потоков
|
||||
|
||||
A.NewQueue.AddFillValue(1) // заполняем весь буфер единичками, прямо перед выполнением
|
||||
as CommandQueue<Buffer> //ToDo нужно только из за issue компилятора #1981, иначе получаем странную ошибку. Когда исправят - можно будет убрать
|
||||
//ToDo нужно только из за issue компилятора #1981
|
||||
as CommandQueue<Buffer>
|
||||
|
||||
);
|
||||
|
||||
A.GetArray1&<integer>.Println; // читаем весь буфер как одномерный массив с элементами типа "integer" и сразу выводим
|
||||
// читаем весь буфер как одномерный массив с элементами типа "integer" и сразу выводим
|
||||
A.GetArray1&<integer>.Println;
|
||||
|
||||
end.
|
||||
</code></pre>
|
||||
|
|
@ -9,6 +9,7 @@
|
|||
body {
|
||||
background-color: #F0F0F0;
|
||||
margin: 0px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.page-base {
|
||||
|
|
@ -86,9 +87,14 @@ body {
|
|||
margin-left: 8px;
|
||||
}
|
||||
.spoiler-wrap {
|
||||
border-left: thin solid;
|
||||
border: solid;
|
||||
border-width: 0px;
|
||||
padding-left: 2px;
|
||||
}
|
||||
.spoiler-name {
|
||||
border: solid;
|
||||
border-width: 0px;
|
||||
}
|
||||
|
||||
.code-block {
|
||||
display: inline-block;
|
||||
|
|
@ -101,6 +107,19 @@ body {
|
|||
|
||||
margin: 0;
|
||||
|
||||
position: relative;
|
||||
}
|
||||
.code-block-copier {
|
||||
cursor: pointer;
|
||||
padding: 2px;
|
||||
|
||||
position: absolute;
|
||||
top: 0;
|
||||
|
||||
border: thin solid;
|
||||
border-radius: 3.7px 0px 3.7px 3.7px;
|
||||
box-shadow: -2px 2px 3px #0000004a;
|
||||
background: linear-gradient(0deg, #f0f0f0, white);
|
||||
}
|
||||
.inline-code {
|
||||
background: #F0F0F0;
|
||||
|
|
@ -142,6 +161,10 @@ const pointed_name_color = "#d1faff";
|
|||
|
||||
var localStorageKey = "";
|
||||
|
||||
const get_style = (el)=>el.currentStyle || window.getComputedStyle(el);
|
||||
|
||||
var spl_resize_event = [];
|
||||
|
||||
/* ============================== *\
|
||||
page load
|
||||
\* ============================== */
|
||||
|
|
@ -368,20 +391,23 @@ const on_end_folder = ()=>{
|
|||
\* ============================== */
|
||||
|
||||
var selected_page = null;
|
||||
var scroll_by_page = {};
|
||||
const is_selected = (name_span)=>(!selected_page || selected_page.name_span!==name_span);
|
||||
const select_page = (new_page)=>{
|
||||
if (selected_page == new_page) return;
|
||||
document.location.hash = new_page.tree_obj.path;
|
||||
fix_element(new_page);
|
||||
|
||||
if (selected_page) {
|
||||
let container = document.getElementById("page-display-container");
|
||||
|
||||
if (selected_page)
|
||||
{
|
||||
scroll_by_page[selected_page.tree_obj.path] = container.scrollTop;
|
||||
selected_page.hidden = true;
|
||||
let name_span = selected_page.name_span;
|
||||
if (name_span) name_span.style.backgroundColor = "inherit";
|
||||
}
|
||||
|
||||
document.getElementById("page-display-container-body").scrollTop = 0;
|
||||
|
||||
selected_page = new_page;
|
||||
if (selected_page)
|
||||
{
|
||||
|
|
@ -396,8 +422,8 @@ const select_page = (new_page)=>{
|
|||
tree_obj = tree_obj.root;
|
||||
}
|
||||
|
||||
container.scrollTop = scroll_by_page[selected_page.tree_obj.path] || 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
const make_smart_link = (lnk, page)=>{
|
||||
|
|
@ -441,8 +467,18 @@ const fix_links = (page)=>{
|
|||
|
||||
const code_words_color = {
|
||||
"pas": {
|
||||
"keyword": ["begin", "end", "var", "uses", "as", "new", "try", "except", "on", "do", "const", "procedure", "function", "lock", "type", "class", "sizeof"],
|
||||
"build-in": ["nil", "integer", "string", "object", "byte"],
|
||||
"keyword": [
|
||||
"begin","end", "var", "uses", "as", "new", "try", "except", "on", "do", "const",
|
||||
"procedure", "function", "lock", "type", "class","record", "sizeof","typeof", "external",
|
||||
"static", "array", "where", "or","and", "public","private", "property","constructor", "default",
|
||||
"of", "if","then","else", "div","mod", "extensionmethod", "while",
|
||||
],
|
||||
"build-in": [
|
||||
"nil", "self", "true", "false",
|
||||
"string","char", "object", "pointer", "single","real",
|
||||
"shortint", "smallint", "integer", "int64",
|
||||
"byte", "word", "longword", "cardinal", "uint64",
|
||||
],
|
||||
"red": ["ToDo"],
|
||||
},
|
||||
"cl-c": {
|
||||
|
|
@ -465,19 +501,21 @@ const fix_element = (page)=>{
|
|||
let wrap = document.createElement('p');
|
||||
wrap.className = "spoiler-wrap";
|
||||
wrap.update = ()=>{
|
||||
wrap.state_span.innerHTML = String.fromCharCode( spoiler.hidden ? 0x25BA : 0x25BC );
|
||||
wrap.style.border = spoiler.hidden ? "none" : null;
|
||||
wrap.style.marginLeft = spoiler.hidden ? "1px" : null;
|
||||
wrap.state_span.innerHTML = String.fromCharCode( spoiler.hidden ? 0x25BA : 0x25BC );
|
||||
wrap.style.borderLeftWidth = spoiler.hidden ? 0 : 1;
|
||||
wrap.name_span.style.borderBottomWidth = spoiler.hidden ? 1 : 0;
|
||||
wrap.style.marginLeft = spoiler.hidden ? 1 : 0;
|
||||
}
|
||||
|
||||
wrap.state_span = document.createElement("span");
|
||||
wrap.update();
|
||||
wrap.append(wrap.state_span);
|
||||
|
||||
wrap.name_span = document.createElement("span");
|
||||
wrap.name_span.className = "spoiler-name";
|
||||
wrap.name_span.innerHTML = spoiler.getAttribute("summary");
|
||||
wrap.append(wrap.name_span);
|
||||
|
||||
wrap.update();
|
||||
wrap.reverse_state = ()=>{
|
||||
spoiler.hidden = !spoiler.hidden;
|
||||
wrap.update();
|
||||
|
|
@ -497,6 +535,8 @@ const fix_element = (page)=>{
|
|||
{
|
||||
let w_to_regex = (w)=>`(?<!\\w)${w}(?!\\w)`;
|
||||
|
||||
let code_html = code.innerHTML;
|
||||
|
||||
// Автоопределение языка кода
|
||||
if (!code.className)
|
||||
{
|
||||
|
|
@ -509,7 +549,7 @@ const fix_element = (page)=>{
|
|||
for (let wordt in code_words_color[lang_name])
|
||||
for (let w of code_words_color[lang_name][wordt])
|
||||
{
|
||||
var m = code.innerHTML.match(new RegExp( w_to_regex(w), "gi" ));
|
||||
var m = code_html.match(new RegExp( w_to_regex(w), "gi" ));
|
||||
if (m) c += m.length;
|
||||
}
|
||||
|
||||
|
|
@ -534,13 +574,13 @@ const fix_element = (page)=>{
|
|||
let curr_cw = code_words_color[lang];
|
||||
if (!curr_cw) curr_cw = code_words_color["default"];
|
||||
for (let wordt in curr_cw)
|
||||
code.innerHTML = code.innerHTML.replace(
|
||||
code_html = code_html.replace(
|
||||
new RegExp(curr_cw[wordt].map(w_to_regex).join('|'),"gi"),
|
||||
w=> `<span class="code-${wordt}">${w}</span>`
|
||||
);
|
||||
}
|
||||
|
||||
// Подсветка скобок
|
||||
// Выделение скобок
|
||||
{
|
||||
var br_types = {
|
||||
op: ["(", "[", "{", "<", "'"],
|
||||
|
|
@ -548,11 +588,27 @@ const fix_element = (page)=>{
|
|||
}
|
||||
for (let op in br_types)
|
||||
for (let i=0; i<br_types[op].length; i++)
|
||||
code.innerHTML = code.innerHTML.replace(
|
||||
code_html = code_html.replace(
|
||||
new RegExp('\\'+br_types[op][i], "g"),
|
||||
`<span class=bracket ${ op=="op" ? "op=true" : "" } bt=${i}>${br_types[op][i]}</span>`
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
// Выделение первой строки
|
||||
if (code.parentElement.tagName == "PRE")
|
||||
{
|
||||
let ind = code_html.indexOf('\n');
|
||||
if (ind != code_html.length-1)
|
||||
code_html = `<span class="code-first-line">${code_html.slice(0,ind)}</span>${code_html.slice(ind)}`;
|
||||
}
|
||||
|
||||
code.innerHTML = code_html;
|
||||
code.firstLine = code.children[0];
|
||||
if (code.firstLine && code.firstLine.className != "code-first-line") delete code.firstLine;
|
||||
|
||||
// Подсветка скобок
|
||||
{
|
||||
let br_st = [];
|
||||
for (let obj2 of code.getElementsByClassName("bracket"))
|
||||
{
|
||||
|
|
@ -615,6 +671,80 @@ const fix_element = (page)=>{
|
|||
|
||||
}
|
||||
|
||||
page.style.visibility = "hidden";
|
||||
page.hidden = false;
|
||||
|
||||
for (let code of page.getElementsByTagName('code'))
|
||||
{
|
||||
if (code.firstLine)
|
||||
{
|
||||
let pre = code.parentElement;
|
||||
|
||||
let copy_button = document.createElement('div');
|
||||
copy_button.className = "code-block-copier";
|
||||
copy_button.innerText = "Копировать";
|
||||
copy_button.style.visibility = "hidden";
|
||||
pre.append(copy_button);
|
||||
|
||||
copy_button.addEventListener("click", ()=>{
|
||||
|
||||
if (document.selection) { // IE
|
||||
var range = document.body.createTextRange();
|
||||
range.moveToElementText(code);
|
||||
range.select();
|
||||
} else if (window.getSelection) { // other browsers
|
||||
var range = document.createRange();
|
||||
range.selectNode(code);
|
||||
window.getSelection().removeAllRanges();
|
||||
window.getSelection().addRange(range);
|
||||
}
|
||||
|
||||
var text = code.innerText;
|
||||
navigator.clipboard.writeText(text.substring(0,text.length-1));
|
||||
});
|
||||
|
||||
copy_button.reset_right = ()=>{
|
||||
pre_st = get_style(pre);
|
||||
let container = document.getElementById("page-display-container");
|
||||
let x = pre.getBoundingClientRect().right - (container.getBoundingClientRect().left+container.clientWidth);
|
||||
if (x<0) x = 0; else
|
||||
{
|
||||
let max_x = pre.offsetWidth - copy_button.offsetWidth;
|
||||
if (x>max_x) x = max_x;
|
||||
}
|
||||
copy_button.style.right = x;
|
||||
};
|
||||
let try_reset_right = ()=>{
|
||||
if (!copy_button.hidden)
|
||||
copy_button.reset_right();
|
||||
};
|
||||
spl_resize_event.push(try_reset_right);
|
||||
window.addEventListener("resize", try_reset_right);
|
||||
|
||||
pre.addEventListener("mouseenter", ()=>{
|
||||
copy_button.hidden = false;
|
||||
copy_button.reset_right();
|
||||
});
|
||||
pre.addEventListener("mouseleave", ()=>copy_button.hidden = true);
|
||||
|
||||
copy_button.addEventListener("mousedown", ()=>copy_button.style.background = "linear-gradient(180deg, rgb(240, 240, 240), white)");
|
||||
copy_button.addEventListener("mouseup", ()=>copy_button.style.background = "linear-gradient( 0deg, rgb(240, 240, 240), white)");
|
||||
copy_button.addEventListener("mouseleave", ()=>copy_button.style.background = "linear-gradient( 0deg, rgb(240, 240, 240), white)");
|
||||
|
||||
pre.style.minWidth =
|
||||
code.firstLine.offsetWidth +
|
||||
copy_button.offsetWidth +
|
||||
0
|
||||
;
|
||||
|
||||
copy_button.hidden = true;
|
||||
copy_button.style.visibility = null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
page.hidden = true;
|
||||
page.style.visibility = null;
|
||||
}
|
||||
|
||||
/* ============================== *\
|
||||
|
|
@ -623,11 +753,21 @@ const fix_element = (page)=>{
|
|||
|
||||
{
|
||||
if (document.location.hash)
|
||||
define_broken_lnk(
|
||||
decodeURIComponent(document.location.hash.substr(1)),
|
||||
{
|
||||
let get_hash = ()=>decodeURIComponent(document.location.hash.substr(1));
|
||||
let define_hash_lnk = ()=>define_broken_lnk(
|
||||
get_hash(),
|
||||
"document.location.hash",
|
||||
page=>select_page(page)
|
||||
);
|
||||
define_hash_lnk();
|
||||
window.addEventListener("hashchange", ()=>{
|
||||
let hash_page = page_by_path[get_hash()];
|
||||
if (hash_page)
|
||||
select_page(hash_page); else
|
||||
define_hash_lnk();
|
||||
});
|
||||
}
|
||||
|
||||
let page_select = document.getElementById("page-select");
|
||||
let page_display = document.getElementById("page-display");
|
||||
|
|
@ -640,8 +780,8 @@ const fix_element = (page)=>{
|
|||
{
|
||||
let par = cont.parentElement;
|
||||
par.update_cont = (w)=>{
|
||||
cont.style.width = w-15 + "px";
|
||||
cont.style.height = wh-15 + "px";
|
||||
cont.style.width = w-15;
|
||||
cont.style.height = wh-15;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -666,10 +806,13 @@ const fix_element = (page)=>{
|
|||
|
||||
page_select.update_cont(spl_X);
|
||||
page_display.update_cont(w2);
|
||||
|
||||
for (let handler of spl_resize_event)
|
||||
handler();
|
||||
}
|
||||
reset_spl();
|
||||
|
||||
window.onresize = ()=>reset_spl();
|
||||
window.addEventListener("resize", ()=>reset_spl());
|
||||
|
||||
splitter.addEventListener("dblclick", ()=>{
|
||||
let w = 0;
|
||||
|
|
@ -679,7 +822,7 @@ const fix_element = (page)=>{
|
|||
if (n.clientWidth>w) w = n.clientWidth;
|
||||
|
||||
let get_margin = (el)=>{
|
||||
let style = el.currentStyle || window.getComputedStyle(el);
|
||||
let style = get_style(el);
|
||||
return parseFloat(style.marginLeft) + parseFloat(style.marginRight);
|
||||
}
|
||||
|
||||
|
|
@ -716,9 +859,9 @@ window.onload = ()=>{
|
|||
}
|
||||
</script>
|
||||
<div id="page-1" page_name="" hidden=true>
|
||||
<p><code>ToDo</code> модуля OpenGLABC пока что не существует. Когда то он появится, но пока что есть только это сообщение.</p>
|
||||
<p><code>ToDo</code> модуля <code>OpenGLABC</code> пока что не существует. Когда то он появится, но пока что есть только это сообщение.</p>
|
||||
<p>Если хотите понять, было ли это сообщение оставлено тут 10 лет назад и забыто - вот дата, когда автор сообщения последний раз прочитал его:<br />
|
||||
08.01.2020</p>
|
||||
03.02.2020</p>
|
||||
</div>
|
||||
<script>on_start_folder("GL ABC", document.getElementById("page-1"))</script>
|
||||
<script>on_end_folder()</script>
|
||||
78324
bin/Lib/OpenGL.pas
78324
bin/Lib/OpenGL.pas
File diff suppressed because it is too large
Load diff
Loading…
Reference in a new issue