LibWeb: Implement more WebGL calls

This commit is contained in:
Aliaksandr Kalenik 2024-12-01 00:09:41 +01:00 committed by Alexander Kalenik
commit f3a24d1569
Notes: github-actions[bot] 2024-12-03 22:36:58 +00:00
5 changed files with 261 additions and 80 deletions

View file

@ -6,11 +6,11 @@
#pragma once
typedef unsigned int GLenum;
typedef unsigned char GLboolean;
typedef int GLint;
typedef int GLsizei;
typedef float GLfloat;
typedef double GLdouble;
typedef GLfloat GLclampf;
typedef unsigned int GLbitfield;
#include <LibGC/Root.h>
#include <LibWeb/Forward.h>
namespace Web::WebGL {
using GLenum = unsigned int;
}

View file

@ -3,6 +3,9 @@ typedef boolean GLboolean;
typedef unsigned long GLbitfield;
typedef long GLint;
typedef long GLsizei;
typedef long long GLintptr;
typedef unsigned long GLuint;
typedef long long GLsizeiptr;
typedef unrestricted float GLfloat;
typedef unrestricted float GLclampf;

View file

@ -1,5 +1,14 @@
#import <HTML/HTMLCanvasElement.idl>
#import <WebGL/Types.idl>
#import <WebGL/WebGLActiveInfo.idl>
#import <WebGL/WebGLBuffer.idl>
#import <WebGL/WebGLObject.idl>
#import <WebGL/WebGLProgram.idl>
#import <WebGL/WebGLShader.idl>
#import <WebGL/WebGLTexture.idl>
#import <WebGL/WebGLUniformLocation.idl>
#import <WebGL/WebGLRenderbuffer.idl>
#import <WebGL/WebGLFramebuffer.idl>
dictionary WebGLContextAttributes {
boolean alpha = true;
@ -36,80 +45,80 @@ interface mixin WebGLRenderingContextBase {
[FIXME] object? getExtension(DOMString name);
undefined activeTexture(GLenum texture);
[FIXME] undefined attachShader(WebGLProgram program, WebGLShader shader);
undefined attachShader(WebGLProgram program, WebGLShader shader);
[FIXME] undefined bindAttribLocation(WebGLProgram program, GLuint index, DOMString name);
[FIXME] undefined bindBuffer(GLenum target, WebGLBuffer? buffer);
undefined bindBuffer(GLenum target, WebGLBuffer? buffer);
[FIXME] undefined bindFramebuffer(GLenum target, WebGLFramebuffer? framebuffer);
[FIXME] undefined bindRenderbuffer(GLenum target, WebGLRenderbuffer? renderbuffer);
[FIXME] undefined bindTexture(GLenum target, WebGLTexture? texture);
[FIXME] undefined blendColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha);
[FIXME] undefined blendEquation(GLenum mode);
[FIXME] undefined blendEquationSeparate(GLenum modeRGB, GLenum modeAlpha);
[FIXME] undefined blendFunc(GLenum sfactor, GLenum dfactor);
[FIXME] undefined blendFuncSeparate(GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha);
undefined bindTexture(GLenum target, WebGLTexture? texture);
undefined blendColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha);
undefined blendEquation(GLenum mode);
undefined blendEquationSeparate(GLenum modeRGB, GLenum modeAlpha);
undefined blendFunc(GLenum sfactor, GLenum dfactor);
undefined blendFuncSeparate(GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha);
[FIXME] GLenum checkFramebufferStatus(GLenum target);
GLenum checkFramebufferStatus(GLenum target);
undefined clear(GLbitfield mask);
undefined clearColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha);
undefined clearDepth(GLclampf depth);
undefined clearStencil(GLint s);
undefined colorMask(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha);
[FIXME] undefined compileShader(WebGLShader shader);
undefined compileShader(WebGLShader shader);
[FIXME] undefined copyTexImage2D(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border);
[FIXME] undefined copyTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height);
[FIXME] WebGLBuffer? createBuffer();
WebGLBuffer? createBuffer();
[FIXME] WebGLFramebuffer? createFramebuffer();
[FIXME] WebGLProgram? createProgram();
WebGLProgram? createProgram();
[FIXME] WebGLRenderbuffer? createRenderbuffer();
[FIXME] WebGLShader? createShader(GLenum type);
[FIXME] WebGLTexture? createTexture();
WebGLShader? createShader(GLenum type);
WebGLTexture? createTexture();
undefined cullFace(GLenum mode);
[FIXME] undefined deleteBuffer(WebGLBuffer? buffer);
[FIXME] undefined deleteFramebuffer(WebGLFramebuffer? framebuffer);
[FIXME] undefined deleteProgram(WebGLProgram? program);
undefined deleteProgram(WebGLProgram? program);
[FIXME] undefined deleteRenderbuffer(WebGLRenderbuffer? renderbuffer);
[FIXME] undefined deleteShader(WebGLShader? shader);
undefined deleteShader(WebGLShader? shader);
[FIXME] undefined deleteTexture(WebGLTexture? texture);
undefined depthFunc(GLenum func);
undefined depthMask(GLboolean flag);
undefined depthRange(GLclampf zNear, GLclampf zFar);
[FIXME] undefined detachShader(WebGLProgram program, WebGLShader shader);
[FIXME] undefined disable(GLenum cap);
[FIXME] undefined disableVertexAttribArray(GLuint index);
[FIXME] undefined drawArrays(GLenum mode, GLint first, GLsizei count);
[FIXME] undefined drawElements(GLenum mode, GLsizei count, GLenum type, GLintptr offset);
undefined detachShader(WebGLProgram program, WebGLShader shader);
undefined disable(GLenum cap);
undefined disableVertexAttribArray(GLuint index);
undefined drawArrays(GLenum mode, GLint first, GLsizei count);
undefined drawElements(GLenum mode, GLsizei count, GLenum type, GLintptr offset);
[FIXME] undefined enable(GLenum cap);
[FIXME] undefined enableVertexAttribArray(GLuint index);
undefined enable(GLenum cap);
undefined enableVertexAttribArray(GLuint index);
undefined finish();
undefined flush();
[FIXME] undefined framebufferRenderbuffer(GLenum target, GLenum attachment, GLenum renderbuffertarget, WebGLRenderbuffer? renderbuffer);
[FIXME] undefined framebufferTexture2D(GLenum target, GLenum attachment, GLenum textarget, WebGLTexture? texture, GLint level);
undefined frontFace(GLenum mode);
[FIXME] undefined generateMipmap(GLenum target);
undefined generateMipmap(GLenum target);
[FIXME] WebGLActiveInfo? getActiveAttrib(WebGLProgram program, GLuint index);
[FIXME] WebGLActiveInfo? getActiveUniform(WebGLProgram program, GLuint index);
[FIXME] sequence<WebGLShader>? getAttachedShaders(WebGLProgram program);
[FIXME] GLint getAttribLocation(WebGLProgram program, DOMString name);
GLint getAttribLocation(WebGLProgram program, DOMString name);
[FIXME] any getBufferParameter(GLenum target, GLenum pname);
[FIXME] any getParameter(GLenum pname);
any getParameter(GLenum pname);
GLenum getError();
[FIXME] any getFramebufferAttachmentParameter(GLenum target, GLenum attachment, GLenum pname);
[FIXME] any getProgramParameter(WebGLProgram program, GLenum pname);
any getProgramParameter(WebGLProgram program, GLenum pname);
[FIXME] DOMString? getProgramInfoLog(WebGLProgram program);
[FIXME] any getRenderbufferParameter(GLenum target, GLenum pname);
[FIXME] any getShaderParameter(WebGLShader shader, GLenum pname);
any getShaderParameter(WebGLShader shader, GLenum pname);
[FIXME] WebGLShaderPrecisionFormat? getShaderPrecisionFormat(GLenum shadertype, GLenum precisiontype);
[FIXME] DOMString? getShaderInfoLog(WebGLShader shader);
@ -119,65 +128,65 @@ interface mixin WebGLRenderingContextBase {
[FIXME] any getUniform(WebGLProgram program, WebGLUniformLocation location);
[FIXME] WebGLUniformLocation? getUniformLocation(WebGLProgram program, DOMString name);
WebGLUniformLocation? getUniformLocation(WebGLProgram program, DOMString name);
[FIXME] any getVertexAttrib(GLuint index, GLenum pname);
[FIXME] GLintptr getVertexAttribOffset(GLuint index, GLenum pname);
[FIXME] undefined hint(GLenum target, GLenum mode);
[FIXME] GLboolean isBuffer(WebGLBuffer? buffer);
[FIXME] GLboolean isEnabled(GLenum cap);
[FIXME] GLboolean isFramebuffer(WebGLFramebuffer? framebuffer);
[FIXME] GLboolean isProgram(WebGLProgram? program);
[FIXME] GLboolean isRenderbuffer(WebGLRenderbuffer? renderbuffer);
[FIXME] GLboolean isShader(WebGLShader? shader);
[FIXME] GLboolean isTexture(WebGLTexture? texture);
undefined hint(GLenum target, GLenum mode);
GLboolean isBuffer(WebGLBuffer? buffer);
GLboolean isEnabled(GLenum cap);
GLboolean isFramebuffer(WebGLFramebuffer? framebuffer);
GLboolean isProgram(WebGLProgram? program);
GLboolean isRenderbuffer(WebGLRenderbuffer? renderbuffer);
GLboolean isShader(WebGLShader? shader);
GLboolean isTexture(WebGLTexture? texture);
undefined lineWidth(GLfloat width);
[FIXME] undefined linkProgram(WebGLProgram program);
[FIXME] undefined pixelStorei(GLenum pname, GLint param);
undefined linkProgram(WebGLProgram program);
undefined pixelStorei(GLenum pname, GLint param);
undefined polygonOffset(GLfloat factor, GLfloat units);
[FIXME] undefined renderbufferStorage(GLenum target, GLenum internalformat, GLsizei width, GLsizei height);
[FIXME] undefined sampleCoverage(GLclampf value, GLboolean invert);
undefined renderbufferStorage(GLenum target, GLenum internalformat, GLsizei width, GLsizei height);
undefined sampleCoverage(GLclampf value, GLboolean invert);
undefined scissor(GLint x, GLint y, GLsizei width, GLsizei height);
[FIXME] undefined shaderSource(WebGLShader shader, DOMString source);
undefined shaderSource(WebGLShader shader, DOMString source);
[FIXME] undefined stencilFunc(GLenum func, GLint ref, GLuint mask);
[FIXME] undefined stencilFuncSeparate(GLenum face, GLenum func, GLint ref, GLuint mask);
[FIXME] undefined stencilMask(GLuint mask);
[FIXME] undefined stencilMaskSeparate(GLenum face, GLuint mask);
undefined stencilFunc(GLenum func, GLint ref, GLuint mask);
undefined stencilFuncSeparate(GLenum face, GLenum func, GLint ref, GLuint mask);
undefined stencilMask(GLuint mask);
undefined stencilMaskSeparate(GLenum face, GLuint mask);
undefined stencilOp(GLenum fail, GLenum zfail, GLenum zpass);
undefined stencilOpSeparate(GLenum face, GLenum fail, GLenum zfail, GLenum zpass);
[FIXME] undefined texParameterf(GLenum target, GLenum pname, GLfloat param);
[FIXME] undefined texParameteri(GLenum target, GLenum pname, GLint param);
undefined texParameterf(GLenum target, GLenum pname, GLfloat param);
undefined texParameteri(GLenum target, GLenum pname, GLint param);
[FIXME] undefined uniform1f(WebGLUniformLocation? location, GLfloat x);
[FIXME] undefined uniform2f(WebGLUniformLocation? location, GLfloat x, GLfloat y);
[FIXME] undefined uniform3f(WebGLUniformLocation? location, GLfloat x, GLfloat y, GLfloat z);
[FIXME] undefined uniform4f(WebGLUniformLocation? location, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
undefined uniform1f(WebGLUniformLocation? location, GLfloat x);
undefined uniform2f(WebGLUniformLocation? location, GLfloat x, GLfloat y);
undefined uniform3f(WebGLUniformLocation? location, GLfloat x, GLfloat y, GLfloat z);
undefined uniform4f(WebGLUniformLocation? location, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
[FIXME] undefined uniform1i(WebGLUniformLocation? location, GLint x);
[FIXME] undefined uniform2i(WebGLUniformLocation? location, GLint x, GLint y);
[FIXME] undefined uniform3i(WebGLUniformLocation? location, GLint x, GLint y, GLint z);
[FIXME] undefined uniform4i(WebGLUniformLocation? location, GLint x, GLint y, GLint z, GLint w);
undefined uniform1i(WebGLUniformLocation? location, GLint x);
undefined uniform2i(WebGLUniformLocation? location, GLint x, GLint y);
undefined uniform3i(WebGLUniformLocation? location, GLint x, GLint y, GLint z);
undefined uniform4i(WebGLUniformLocation? location, GLint x, GLint y, GLint z, GLint w);
[FIXME] undefined useProgram(WebGLProgram? program);
[FIXME] undefined validateProgram(WebGLProgram program);
undefined useProgram(WebGLProgram? program);
undefined validateProgram(WebGLProgram program);
[FIXME] undefined vertexAttrib1f(GLuint index, GLfloat x);
[FIXME] undefined vertexAttrib2f(GLuint index, GLfloat x, GLfloat y);
[FIXME] undefined vertexAttrib3f(GLuint index, GLfloat x, GLfloat y, GLfloat z);
[FIXME] undefined vertexAttrib4f(GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
undefined vertexAttrib1f(GLuint index, GLfloat x);
undefined vertexAttrib2f(GLuint index, GLfloat x, GLfloat y);
undefined vertexAttrib3f(GLuint index, GLfloat x, GLfloat y, GLfloat z);
undefined vertexAttrib4f(GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
[FIXME] undefined vertexAttrib1fv(GLuint index, Float32List values);
[FIXME] undefined vertexAttrib2fv(GLuint index, Float32List values);
[FIXME] undefined vertexAttrib3fv(GLuint index, Float32List values);
[FIXME] undefined vertexAttrib4fv(GLuint index, Float32List values);
[FIXME] undefined vertexAttribPointer(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, GLintptr offset);
undefined vertexAttribPointer(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, GLintptr offset);
undefined viewport(GLint x, GLint y, GLsizei width, GLsizei height);

View file

@ -1,7 +1,13 @@
#import <WebGL/Types.idl>
// FIXME: BufferSource should be a Float32Array
typedef (BufferSource or sequence<GLfloat>) Float32List;
// https://registry.khronos.org/webgl/specs/latest/1.0/#5.14
interface mixin WebGLRenderingContextOverloads {
[FIXME] undefined bufferData(GLenum target, GLsizeiptr size, GLenum usage);
[FIXME] undefined bufferData(GLenum target, AllowSharedBufferSource? data, GLenum usage);
undefined bufferData(GLenum target, GLsizeiptr size, GLenum usage);
// FIXME: BufferSource is really a AllowSharedBufferSource
undefined bufferData(GLenum target, BufferSource? data, GLenum usage);
[FIXME] undefined bufferSubData(GLenum target, GLintptr offset, AllowSharedBufferSource data);
[FIXME] undefined compressedTexImage2D(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, [AllowShared] ArrayBufferView data);
@ -15,17 +21,18 @@ interface mixin WebGLRenderingContextOverloads {
[FIXME] undefined texSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, [AllowShared] ArrayBufferView? pixels);
[FIXME] undefined texSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLenum format, GLenum type, TexImageSource source); // May throw DOMException
[FIXME] undefined uniform1fv(WebGLUniformLocation? location, Float32List v);
[FIXME] undefined uniform2fv(WebGLUniformLocation? location, Float32List v);
[FIXME] undefined uniform3fv(WebGLUniformLocation? location, Float32List v);
[FIXME] undefined uniform4fv(WebGLUniformLocation? location, Float32List v);
undefined uniform1fv(WebGLUniformLocation? location, Float32List v);
undefined uniform2fv(WebGLUniformLocation? location, Float32List v);
undefined uniform3fv(WebGLUniformLocation? location, Float32List v);
undefined uniform4fv(WebGLUniformLocation? location, Float32List v);
[FIXME] undefined uniform1iv(WebGLUniformLocation? location, Int32List v);
[FIXME] undefined uniform2iv(WebGLUniformLocation? location, Int32List v);
[FIXME] undefined uniform3iv(WebGLUniformLocation? location, Int32List v);
[FIXME] undefined uniform4iv(WebGLUniformLocation? location, Int32List v);
[FIXME] undefined uniformMatrix2fv(WebGLUniformLocation? location, GLboolean transpose, Float32List value);
[FIXME] undefined uniformMatrix3fv(WebGLUniformLocation? location, GLboolean transpose, Float32List value);
[FIXME] undefined uniformMatrix4fv(WebGLUniformLocation? location, GLboolean transpose, Float32List value);
// FIXME: Float32Array should be a Float32List
undefined uniformMatrix2fv(WebGLUniformLocation? location, GLboolean transpose, Float32List value);
undefined uniformMatrix3fv(WebGLUniformLocation? location, GLboolean transpose, Float32List value);
undefined uniformMatrix4fv(WebGLUniformLocation? location, GLboolean transpose, Float32List value);
};

View file

@ -123,6 +123,15 @@ ErrorOr<int> serenity_main(Main::Arguments arguments)
namespace Web::WebGL {
static Vector<GLchar> null_terminated_string(StringView string)
{
Vector<GLchar> result;
for (auto c : string.bytes())
result.append(c);
result.append('\\0');
return result;
}
WebGLRenderingContextImpl::WebGLRenderingContextImpl(JS::Realm& realm, NonnullOwnPtr<OpenGLContext> context)
: m_realm(realm)
, m_context(move(context))
@ -209,6 +218,140 @@ public:
function_impl_generator.append(" m_context->notify_content_will_change();\n"sv);
}
if (function.name == "createBuffer"sv) {
function_impl_generator.append(R"~~~(
GLuint handle = 0;
glGenBuffers(1, &handle);
return WebGLBuffer::create(m_realm, handle);
)~~~");
continue;
}
if (function.name == "createTexture"sv) {
function_impl_generator.append(R"~~~(
GLuint handle = 0;
glGenTextures(1, &handle);
return WebGLTexture::create(m_realm, handle);
)~~~");
continue;
}
if (function.name == "shaderSource"sv) {
function_impl_generator.append(R"~~~(
Vector<GLchar*> strings;
auto string = null_terminated_string(source);
strings.append(string.data());
Vector<GLint> length;
length.append(source.bytes().size());
glShaderSource(shader->handle(), 1, strings.data(), length.data());
)~~~");
continue;
}
if (function.name == "getAttribLocation"sv) {
function_impl_generator.append(R"~~~(
auto name_str = null_terminated_string(name);
return glGetAttribLocation(program->handle(), name_str.data());
)~~~");
continue;
}
if (function.name == "vertexAttribPointer"sv) {
function_impl_generator.append(R"~~~(
glVertexAttribPointer(index, size, type, normalized, stride, reinterpret_cast<void*>(offset));
)~~~");
continue;
}
if (function.name == "getShaderParameter"sv) {
function_impl_generator.append(R"~~~(
GLint result = 0;
glGetShaderiv(shader->handle(), pname, &result);
return JS::Value(result);
)~~~");
continue;
}
if (function.name == "getProgramParameter"sv) {
function_impl_generator.append(R"~~~(
GLint result = 0;
glGetProgramiv(program->handle(), pname, &result);
return JS::Value(result);
)~~~");
continue;
}
if (function.name == "bufferData"sv && function.overload_index == 0) {
function_impl_generator.append(R"~~~(
glBufferData(target, size, 0, usage);
)~~~");
continue;
}
if (function.name == "getUniformLocation"sv) {
function_impl_generator.append(R"~~~(
auto name_str = null_terminated_string(name);
return WebGLUniformLocation::create(m_realm, glGetUniformLocation(program->handle(), name_str.data()));
)~~~");
continue;
}
if (function.name == "drawElements"sv) {
function_impl_generator.append(R"~~~(
glDrawElements(mode, count, type, reinterpret_cast<void*>(offset));
needs_to_present();
)~~~");
continue;
}
if (function.name.starts_with("uniformMatrix"sv)) {
auto number_of_matrix_elements = function.name.substring_view(13, 1);
function_impl_generator.set("number_of_matrix_elements", number_of_matrix_elements);
function_impl_generator.append(R"~~~(
auto matrix_size = @number_of_matrix_elements@ * @number_of_matrix_elements@;
if (value.has<Vector<float>>()) {
auto& data = value.get<Vector<float>>();
glUniformMatrix@number_of_matrix_elements@fv(location->handle(), data.size() / matrix_size, transpose, data.data());
return;
}
auto& typed_array_base = static_cast<JS::TypedArrayBase&>(*value.get<GC::Root<WebIDL::BufferSource>>()->raw_object());
auto& float32_array = verify_cast<JS::Float32Array>(typed_array_base);
float const* data = float32_array.data().data();
auto count = float32_array.array_length().length() / matrix_size;
glUniformMatrix@number_of_matrix_elements@fv(location->handle(), count, transpose, data);
)~~~");
continue;
}
if (function.name == "uniform1fv"sv || function.name == "uniform2fv"sv || function.name == "uniform3fv"sv || function.name == "uniform4fv"sv) {
auto number_of_matrix_elements = function.name.substring_view(7, 1);
function_impl_generator.set("number_of_matrix_elements", number_of_matrix_elements);
function_impl_generator.append(R"~~~(
if (v.has<Vector<float>>()) {
auto& data = v.get<Vector<float>>();
glUniform@number_of_matrix_elements@fv(location->handle(), data.size() / @number_of_matrix_elements@, data.data());
return;
}
auto& typed_array_base = static_cast<JS::TypedArrayBase&>(*v.get<GC::Root<WebIDL::BufferSource>>()->raw_object());
auto& float32_array = verify_cast<JS::Float32Array>(typed_array_base);
float const* data = float32_array.data().data();
auto count = float32_array.array_length().length() / @number_of_matrix_elements@;
glUniform@number_of_matrix_elements@fv(location->handle(), count, data);
)~~~");
continue;
}
if (function.name == "getParameter"sv) {
function_impl_generator.append(R"~~~(
GLint result = 0;
glGetIntegerv(pname, &result);
return JS::Value(result);
)~~~");
continue;
}
Vector<ByteString> gl_call_arguments;
for (size_t i = 0; i < function.parameters.size(); ++i) {
auto const& parameter = function.parameters[i];
@ -224,6 +367,25 @@ public:
gl_call_arguments.append(ByteString::formatted("{} ? {}->handle() : 0", parameter.name, parameter.name));
continue;
}
if (parameter.type->name() == "BufferSource"sv) {
function_impl_generator.set("buffer_source_name", parameter.name);
function_impl_generator.append(R"~~~(
void const* ptr = nullptr;
size_t byte_size = 0;
if (@buffer_source_name@->is_typed_array_base()) {
auto& typed_array_base = static_cast<JS::TypedArrayBase&>(*@buffer_source_name@->raw_object());
ptr = typed_array_base.viewed_array_buffer()->buffer().data();
byte_size = typed_array_base.viewed_array_buffer()->byte_length();
} else if (@buffer_source_name@->is_data_view()) {
VERIFY_NOT_REACHED();
} else {
VERIFY_NOT_REACHED();
}
)~~~");
gl_call_arguments.append(ByteString::formatted("byte_size"));
gl_call_arguments.append(ByteString::formatted("ptr"));
continue;
}
VERIFY_NOT_REACHED();
}