From: yu.dongliang <18588496441@163.com> Date: Fri, 20 Sep 2024 12:07:20 +0000 (+0800) Subject: support HTML X-Git-Url: http://baseworks.info/?a=commitdiff_plain;h=b63e932410afc112024c4833b034c68508ad1020;p=abc.git support HTML --- diff --git a/examples/img.html b/examples/img.html new file mode 100644 index 0000000..47cfb78 --- /dev/null +++ b/examples/img.html @@ -0,0 +1,9 @@ + + + +图片 + + + + + diff --git a/examples/img.png b/examples/img.png new file mode 100644 index 0000000..a3a560b Binary files /dev/null and b/examples/img.png differ diff --git a/ffmpeg/Makefile b/ffmpeg/Makefile new file mode 100644 index 0000000..1b8f12a --- /dev/null +++ b/ffmpeg/Makefile @@ -0,0 +1,17 @@ +CFILES += ../util/scf_string.c + +CFILES += main.c +CFILES += abc_ffmpeg_img.c + +CFLAGS += -g +CFLAGS += -I../util + +LDFLAGS += -lavformat -lavcodec -lavfilter -lavutil +LDFLAGS += -lcairo +LDFLAGS += -ldl + +all: + gcc $(CFLAGS) $(CFILES) $(LDFLAGS) + +clean: + rm *.o diff --git a/ffmpeg/abc_ffmpeg.h b/ffmpeg/abc_ffmpeg.h new file mode 100644 index 0000000..60c8620 --- /dev/null +++ b/ffmpeg/abc_ffmpeg.h @@ -0,0 +1,34 @@ +#ifndef ABC_FFMPEG_H +#define ABC_FFMPEG_H + +#include"scf_def.h" + +#include "libavformat/avformat.h" +#include "libavcodec/avcodec.h" +#include "libavutil/avutil.h" +#include "libavutil/opt.h" +#include "libavfilter/avfilter.h" +#include "libavfilter/buffersrc.h" +#include "libavfilter/buffersink.h" + +typedef struct { + AVFormatContext* fmt_ctx; + AVCodecContext* dec_ctx; + int video_index; + + AVFilterContext* buffersrc_ctx; + AVFilterContext* buffersink_ctx; + AVFilterGraph* filter_graph; + + int width; + int height; +} abc_img_t; + + +int abc_img_open (abc_img_t** pimg, const char* path); +void abc_img_close(abc_img_t* img); + +// ffmpeg BGRA == cario ARGB, Blue in byte[0]. +int abc_img_read (abc_img_t* img, uint8_t* bgra, int size); + +#endif diff --git a/ffmpeg/abc_ffmpeg_img.c b/ffmpeg/abc_ffmpeg_img.c new file mode 100644 index 0000000..a9bf794 --- /dev/null +++ b/ffmpeg/abc_ffmpeg_img.c @@ -0,0 +1,266 @@ +#include "abc_ffmpeg.h" + +static int __ffmpeg_init(abc_img_t* img, const char* filename) +{ + int ret = avformat_open_input(&img->fmt_ctx, filename, NULL, NULL); + if (ret < 0) { + scf_loge("avformat_open_input, %s\n", av_err2str(ret)); + return ret; + } + + ret = avformat_find_stream_info(img->fmt_ctx, NULL); + if (ret < 0) { + scf_loge("avformat_find_stream_info, %s\n", av_err2str(ret)); + return ret; + } + + AVStream* s = NULL; + AVCodec* c = NULL; + + int i; + for (i = 0; i < img->fmt_ctx->nb_streams; i++) { + s = img->fmt_ctx->streams[i]; + + if (AVMEDIA_TYPE_VIDEO == s->codecpar->codec_type) { + img->video_index = i; + break; + } + } + + if (i == img->fmt_ctx->nb_streams) { + scf_loge("video stream not found\n"); + return -1; + } + + c = avcodec_find_decoder(s->codecpar->codec_id); + if (!c) { + scf_loge("decoder not found, codec_id: %d\n", s->codecpar->codec_id); + return -EINVAL; + } + + img->dec_ctx = avcodec_alloc_context3(c); + if (!img->dec_ctx) { + scf_loge("avcodec_alloc_context3() failed\n"); + return -ENOMEM; + } + + ret = avcodec_parameters_to_context(img->dec_ctx, s->codecpar); + if (ret < 0) { + scf_loge("avcodec_parameters_to_context, %s\n", av_err2str(ret)); + return ret; + } + + ret = avcodec_open2(img->dec_ctx, c, NULL); + if (ret < 0) { + scf_loge("avcodec_parameters_to_context, %s\n", av_err2str(ret)); + return ret; + } + + img->width = img->dec_ctx->width; + img->height = img->dec_ctx->height; + return 0; +} + +static int __init_filters(abc_img_t* img, const char *filters_desc) +{ + char args[512]; + int ret = 0; + + const AVFilter *buffersrc = avfilter_get_by_name("buffer"); + const AVFilter *buffersink = avfilter_get_by_name("buffersink"); + + AVFilterInOut *outputs = avfilter_inout_alloc(); + AVFilterInOut *inputs = avfilter_inout_alloc(); + + AVCodecContext* dec_ctx = img->dec_ctx; + AVStream* s = img->fmt_ctx->streams[img->video_index]; + + enum AVPixelFormat pix_fmts[] = {AV_PIX_FMT_BGRA, AV_PIX_FMT_NONE}; + + img->filter_graph = avfilter_graph_alloc(); + if (!outputs || !inputs || !img->filter_graph) { + ret = AVERROR(ENOMEM); + goto end; + } + + snprintf(args, sizeof(args), + "video_size=%dx%d:pix_fmt=%d:time_base=%d/%d:pixel_aspect=%d/%d", + dec_ctx->width, dec_ctx->height, dec_ctx->pix_fmt, + s->time_base.num, s->time_base.den, + dec_ctx->sample_aspect_ratio.num, dec_ctx->sample_aspect_ratio.den); + + ret = avfilter_graph_create_filter(&img->buffersrc_ctx, buffersrc, "in", args, NULL, img->filter_graph); + if (ret < 0) + goto end; + + ret = avfilter_graph_create_filter(&img->buffersink_ctx, buffersink, "out", NULL, NULL, img->filter_graph); + if (ret < 0) + goto end; + + ret = av_opt_set_int_list(img->buffersink_ctx, "pix_fmts", pix_fmts, AV_PIX_FMT_NONE, AV_OPT_SEARCH_CHILDREN); + if (ret < 0) + goto end; + + outputs->name = av_strdup("in"); + outputs->filter_ctx = img->buffersrc_ctx; + outputs->pad_idx = 0; + outputs->next = NULL; + + inputs->name = av_strdup("out"); + inputs->filter_ctx = img->buffersink_ctx; + inputs->pad_idx = 0; + inputs->next = NULL; + + if ((ret = avfilter_graph_parse_ptr(img->filter_graph, filters_desc, &inputs, &outputs, NULL)) < 0) + goto end; + + if ((ret = avfilter_graph_config(img->filter_graph, NULL)) < 0) + goto end; + +end: + avfilter_inout_free(&inputs); + avfilter_inout_free(&outputs); + return ret; +} + +int abc_img_open(abc_img_t** pimg, const char* path) +{ + if (!pimg || !path) + return -EINVAL; + + abc_img_t* img = calloc(1, sizeof(abc_img_t)); + if (!img) + return -ENOMEM; + + int ret = __ffmpeg_init(img, path); + if (ret < 0) { + abc_img_close(img); + return ret; + } + + *pimg = img; + return 0; +} + +void abc_img_close(abc_img_t* img) +{ + if (img) { + avcodec_free_context(&img->dec_ctx); + avformat_close_input(&img->fmt_ctx); + + if (img->filter_graph) + avfilter_graph_free(&img->filter_graph); + + free(img); + } +} + +int abc_img_read(abc_img_t* img, uint8_t* bgra, int size) +{ + if (!img || !bgra || size < img->width * img->height * 4) + return -EINVAL; + + char filters_desc[256]; + snprintf(filters_desc, sizeof(filters_desc), "scale=%dx%d", img->width, img->height); + + int ret = __init_filters(img, filters_desc); + if (ret < 0) { + scf_loge("ffmpeg_init error\n"); + return ret; + } + + AVFrame* frame = av_frame_alloc(); + if (!frame) + return -ENOMEM; + + AVFrame* frame2 = av_frame_alloc(); + if (!frame2) { + av_frame_free(&frame); + return -ENOMEM; + } + + AVPacket* pkt = av_packet_alloc(); + if (!pkt) { + av_frame_free(&frame); + av_frame_free(&frame2); + return -ENOMEM; + } + + int key_frame = 0; + + while (1) { + ret = av_read_frame(img->fmt_ctx, pkt); + if (ret < 0) { + scf_loge("av_read_frame, %s\n", av_err2str(ret)); + goto end; + } + + if (pkt->stream_index != img->video_index) { + av_packet_unref(pkt); + continue; + } + + if (pkt->flags & AV_PKT_FLAG_KEY) + key_frame++; + + if (key_frame > 0) + break; + + av_packet_unref(pkt); + } + + ret = avcodec_send_packet(img->dec_ctx, pkt); + if (ret < 0) { + scf_loge("avcodec_send_packet, %s\n", av_err2str(ret)); + goto end; + } + + while (ret >= 0) { + ret = avcodec_receive_frame(img->dec_ctx, frame); + + if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) + break; + else if (ret < 0) { + scf_loge("avcodec_receive_frame, %s\n", av_err2str(ret)); + goto end; + } + + frame->pts = frame->best_effort_timestamp; + + ret = av_buffersrc_add_frame_flags(img->buffersrc_ctx, frame, AV_BUFFERSRC_FLAG_KEEP_REF); + if (ret < 0) { + scf_loge("av_buffersrc_add_frame_flags, %s\n", av_err2str(ret)); + goto end; + } + + while (1) { + ret = av_buffersink_get_frame(img->buffersink_ctx, frame2); + + if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) + break; + else if (ret < 0) { + scf_loge("av_buffersink_get_frame, %s\n", av_err2str(ret)); + goto end; + } + + assert(img->width == frame2->width); + assert(img->height == frame2->height); + + scf_logi("frame2->linesize[0]: %d\n", frame2->linesize[0]); + + int i; + for (i = 0; i < frame2->height; i++) + memcpy(bgra + i * frame2->width * 4, frame2->data[0] + i * frame2->linesize[0], frame2->width * 4); + + av_frame_unref(frame2); + } + av_frame_unref(frame); + } + + ret = 0; +end: + av_packet_free(&pkt); + av_frame_free(&frame); + av_frame_free(&frame2); + return ret; +} diff --git a/ffmpeg/main.c b/ffmpeg/main.c new file mode 100644 index 0000000..92093b4 --- /dev/null +++ b/ffmpeg/main.c @@ -0,0 +1,49 @@ +#include +#include"abc_ffmpeg.h" + +int main(int argc, char* argv[]) +{ + abc_img_t* img = NULL; + + if (argc < 2) { + scf_loge("\n"); + return -1; + } + + if (abc_img_open(&img, argv[1]) < 0) { + scf_loge("\n"); + return -1; + } + + scf_logi("img->width: %d, img->height: %d\n", img->width, img->height); + + int size = img->width * img->height * 4; + + uint8_t* rgba = calloc(1, size); + if (!rgba) { + scf_loge("\n"); + return -1; + } + + if (abc_img_read(img, rgba, size) < 0) { + scf_loge("\n"); + return -1; + } + + + cairo_surface_t* surface; + cairo_t* cr; + + surface = cairo_image_surface_create_for_data(rgba, CAIRO_FORMAT_ARGB32, img->width, img->height, img->width * 4); + cr = cairo_create(surface); + + cairo_surface_write_to_png(surface, "1.png"); + + cairo_destroy(cr); + cairo_surface_destroy(surface); + + printf("\n"); + + scf_logi("main ok\n"); + return 0; +} diff --git a/html/abc_html.c b/html/abc_html.c index 1c4791e..a49508b 100644 --- a/html/abc_html.c +++ b/html/abc_html.c @@ -21,6 +21,36 @@ static html_attr_t h1_attrs[] = {"font-size", "32", ABC_HTML_ATTR_FONT_SIZE}, }; +static html_attr_t h2_attrs[] = +{ + {"font", "Liberation Serif", ABC_HTML_ATTR_FONT}, + {"font-size", "28", ABC_HTML_ATTR_FONT_SIZE}, +}; + +static html_attr_t h3_attrs[] = +{ + {"font", "Liberation Serif", ABC_HTML_ATTR_FONT}, + {"font-size", "24", ABC_HTML_ATTR_FONT_SIZE}, +}; + +static html_attr_t h4_attrs[] = +{ + {"font", "Liberation Serif", ABC_HTML_ATTR_FONT}, + {"font-size", "20", ABC_HTML_ATTR_FONT_SIZE}, +}; + +static html_attr_t h5_attrs[] = +{ + {"font", "Liberation Serif", ABC_HTML_ATTR_FONT}, + {"font-size", "16", ABC_HTML_ATTR_FONT_SIZE}, +}; + +static html_attr_t h6_attrs[] = +{ + {"font", "Liberation Serif", ABC_HTML_ATTR_FONT}, + {"font-size", "12", ABC_HTML_ATTR_FONT_SIZE}, +}; + static html_attr_t a_attrs[] = { {"href", "", ABC_HTML_ATTR_HREF}, @@ -29,6 +59,13 @@ static html_attr_t a_attrs[] = {"font-color", "blue", ABC_HTML_ATTR_FONT_COLOR}, }; +static html_attr_t img_attrs[] = +{ + {"src", "", ABC_HTML_ATTR_SRC}, + {"width", "100", ABC_HTML_ATTR_WIDTH}, + {"height", "100", ABC_HTML_ATTR_HEIGHT}, +}; + static html_label_t html_labels[] = { {"html", ABC_HTML, 0, NULL}, @@ -39,7 +76,14 @@ static html_label_t html_labels[] = {"div", ABC_HTML_DIV, 0, NULL}, {"h1", ABC_HTML_H1, sizeof(h1_attrs) / sizeof(h1_attrs[0]), h1_attrs}, - {"a", ABC_HTML_A, sizeof(a_attrs) / sizeof(a_attrs[0]), a_attrs}, + {"h2", ABC_HTML_H2, sizeof(h2_attrs) / sizeof(h2_attrs[0]), h2_attrs}, + {"h3", ABC_HTML_H3, sizeof(h3_attrs) / sizeof(h3_attrs[0]), h3_attrs}, + {"h4", ABC_HTML_H4, sizeof(h4_attrs) / sizeof(h4_attrs[0]), h4_attrs}, + {"h5", ABC_HTML_H5, sizeof(h5_attrs) / sizeof(h5_attrs[0]), h5_attrs}, + {"h6", ABC_HTML_H6, sizeof(h6_attrs) / sizeof(h6_attrs[0]), h6_attrs}, + + {"a", ABC_HTML_A, sizeof(a_attrs) / sizeof(a_attrs[0]), a_attrs}, + {"img", ABC_HTML_IMG, sizeof(img_attrs) / sizeof(img_attrs[0]), img_attrs}, }; static int __html_parse_obj(abc_html_t* html, abc_char_t* c); @@ -308,7 +352,7 @@ static int __html_parse_value(abc_html_t* html, abc_obj_t* attr) scf_string_free(attr->value); attr->value = value; - return '>' == tmp; + return tmp; } static int __html_parse_attr2(abc_html_t* html, abc_obj_t* obj, const html_attr_t* attrs, int n_attrs) @@ -332,13 +376,19 @@ static int __html_parse_attr2(abc_html_t* html, abc_obj_t* obj, const html_attr_ if ('=' == c->c) break; + if ('/' == c->c) { + free(c); + scf_string_free(key); + return '/'; + } + if ('_' == c->c || '-' == c->c || ('a' <= c->c && 'z' >= c->c)) scf_string_cat_cstr_len(key, c->utf8, c->len); else { - scf_loge("invalid char in HTML attribute, file: %s, line: %d\n", - html->file->data, html->n_lines); + scf_loge("invalid char '%c' in HTML attribute, file: %s, line: %d\n", + c->c, html->file->data, html->n_lines); free(c); scf_string_free(key); return -1; @@ -389,13 +439,16 @@ static int __html_parse_attr(abc_html_t* html, abc_obj_t* obj, const html_attr_t { int ret = 0; - while (!ret) { + while (1) { ret = __html_parse_attr2(html, obj, attrs, n_attrs); if (ret < 0) return ret; + + if ('>' == ret || '/' == ret) + break; } - return 0; + return ret; } static int __html_parse_obj(abc_html_t* html, abc_char_t* c) @@ -464,6 +517,7 @@ static int __html_parse_obj(abc_html_t* html, abc_char_t* c) return ret; } + ret = 0; if (' ' == tmp) { ret = __html_parse_attr(html, obj, label->attrs, label->n_attrs); if (ret < 0) { @@ -486,7 +540,25 @@ static int __html_parse_obj(abc_html_t* html, abc_char_t* c) html->current = obj; } - ret = __html_parse_text(html, obj); + if ('/' == ret) { + c = __html_pop_char(html); + if (!c) { + scf_loge("\n"); + return -1; + } + + int tmp = c->c; + + free(c); + c = NULL; + + if ('>' != tmp) { + scf_loge("HTML label '%s' not closed, in file: %s, line: %d\n", + obj->key->data, html->file->data, html->n_lines); + return -1; + } + } else + ret = __html_parse_text(html, obj); html->current = obj->parent; return ret; diff --git a/html/abc_obj.h b/html/abc_obj.h index 431e6f4..f1babf8 100644 --- a/html/abc_obj.h +++ b/html/abc_obj.h @@ -15,18 +15,34 @@ enum abc_objs // 4 ABC_HTML_DIV, + + // 5 ABC_HTML_H1, + ABC_HTML_H2, + ABC_HTML_H3, + ABC_HTML_H4, + ABC_HTML_H5, + ABC_HTML_H6, + + // 11 ABC_HTML_A, ABC_HTML_A_HREF, + // 13 + ABC_HTML_IMG, + ABC_HTML_NB, // total HTML objects ABC_HTML_ATTR_ID, ABC_HTML_ATTR_HREF, + ABC_HTML_ATTR_SRC, ABC_HTML_ATTR_FONT, ABC_HTML_ATTR_FONT_SIZE, ABC_HTML_ATTR_FONT_COLOR, + + ABC_HTML_ATTR_WIDTH, + ABC_HTML_ATTR_HEIGHT, }; struct abc_obj_s diff --git a/ui/Makefile b/ui/Makefile index b06f22c..4dc7d04 100644 --- a/ui/Makefile +++ b/ui/Makefile @@ -8,6 +8,7 @@ CFILES += abc_layout_body.c CFILES += abc_layout_div.c CFILES += abc_layout_h1.c CFILES += abc_layout_a.c +CFILES += abc_layout_img.c CFILES += abc_render.c CFILES += abc_render_html.c @@ -18,16 +19,20 @@ CFILES += abc_render_div.c CFILES += abc_render_h1.c CFILES += abc_render_a.c CFILES += abc_render_a_href.c +CFILES += abc_render_img.c CFILES += ../html/abc_html.c CFILES += ../html/abc_html_util.c CFILES += ../html/abc_obj.c +CFILES += ../ffmpeg/abc_ffmpeg_img.c + CFILES += ../util/scf_string.c CFLAGS += -g -O3 CFLAGS += -I./ CFLAGS += -I../html +CFLAGS += -I../ffmpeg CFLAGS += -I../util CFLAGS += `pkg-config --cflags gtk+-3.0` diff --git a/ui/abc.h b/ui/abc.h index 347e88b..02ac07e 100644 --- a/ui/abc.h +++ b/ui/abc.h @@ -72,4 +72,6 @@ int __init_texture(GLuint* ptex, GLenum format, int w, int h, uint8_t* data); int __init_program(GLuint* pprog, const char* vert_shader, const char* frag_shader); +int __init_buffers(GLuint* vao, GLuint buffers[2]); + #endif diff --git a/ui/abc_layout.c b/ui/abc_layout.c index 3ebf72c..b205320 100644 --- a/ui/abc_layout.c +++ b/ui/abc_layout.c @@ -8,6 +8,7 @@ int abc_layout_body (abc_layout_t* layout, abc_obj_t* root, int width, int heigh int abc_layout_div (abc_layout_t* layout, abc_obj_t* root, int width, int height); int abc_layout_h1 (abc_layout_t* layout, abc_obj_t* root, int width, int height); int abc_layout_a (abc_layout_t* layout, abc_obj_t* root, int width, int height); +int abc_layout_img (abc_layout_t* layout, abc_obj_t* root, int width, int height); static abc_layout_pt abc_layouts[ABC_HTML_NB] = { @@ -18,8 +19,19 @@ static abc_layout_pt abc_layouts[ABC_HTML_NB] = // 4 abc_layout_div, + + abc_layout_h1, + abc_layout_h1, + abc_layout_h1, abc_layout_h1, + abc_layout_h1, + abc_layout_h1, + + // 11 abc_layout_a, + NULL, + + abc_layout_img, }; int abc_layout_obj(abc_layout_t* layout, abc_obj_t* obj, int width, int height) diff --git a/ui/abc_layout_img.c b/ui/abc_layout_img.c new file mode 100644 index 0000000..5744271 --- /dev/null +++ b/ui/abc_layout_img.c @@ -0,0 +1,33 @@ +#include"abc.h" + +int abc_layout_img(abc_layout_t* layout, abc_obj_t* obj, int width, int height) +{ + scf_list_t* l; + abc_obj_t* attr; + + for (l = scf_list_head(&obj->attrs); l != scf_list_sentinel(&obj->attrs); l = scf_list_next(l)) { + attr = scf_list_data(l, abc_obj_t, list); + + switch (attr->type) { + + case ABC_HTML_ATTR_WIDTH: + obj->w = atoi(attr->value->data); + break; + + case ABC_HTML_ATTR_HEIGHT: + obj->h = atoi(attr->value->data); + break; + default: + break; + }; + } + + obj->x = 4; + obj->y = 4; + + obj->w = (obj->w + 3) & ~0x3; + obj->h = (obj->h + 3) & ~0x3; + + scf_logd("%s, w: %d, h: %d\n", obj->text->data, obj->w, obj->h); + return 0; +} diff --git a/ui/abc_render.c b/ui/abc_render.c index d97b6c2..a1485ef 100644 --- a/ui/abc_render.c +++ b/ui/abc_render.c @@ -9,6 +9,7 @@ extern abc_render_t abc_render_div; extern abc_render_t abc_render_h1; extern abc_render_t abc_render_a; extern abc_render_t abc_render_a_href; +extern abc_render_t abc_render_img; static abc_render_t* abc_renders[ABC_HTML_NB] = { @@ -19,9 +20,19 @@ static abc_render_t* abc_renders[ABC_HTML_NB] = // 4 &abc_render_div, + + &abc_render_h1, + &abc_render_h1, + &abc_render_h1, &abc_render_h1, + &abc_render_h1, + &abc_render_h1, + + // 11 &abc_render_a, &abc_render_a_href, + + &abc_render_img, }; int abc_renders_fini() @@ -160,6 +171,29 @@ int __init_texture(GLuint* ptex, GLenum format, int w, int h, uint8_t* data) return 0; } +int __init_buffers(GLuint* vao, GLuint buffers[2]) +{ + glGenBuffers(2, buffers); + glBindBuffer(GL_ARRAY_BUFFER, buffers[0]); + glBufferData(GL_ARRAY_BUFFER, sizeof(vert_array), vert_array, GL_STATIC_DRAW); + glBindBuffer(GL_ARRAY_BUFFER, buffers[1]); + glBufferData(GL_ARRAY_BUFFER, sizeof(texture_array), texture_array, GL_STATIC_DRAW); + + glGenVertexArrays(1, vao); + glBindVertexArray(*vao); + + glBindBuffer(GL_ARRAY_BUFFER, buffers[0]); + glEnableVertexAttribArray(0); + glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, 0); + + glBindBuffer(GL_ARRAY_BUFFER, buffers[1]); + glEnableVertexAttribArray(1); + glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, 0); + + glBindVertexArray(0); + return 0; +} + int __init_program(GLuint* pprog, const char* vert_shader, const char* frag_shader) { GLint status = 0; diff --git a/ui/abc_render_a.c b/ui/abc_render_a.c index 02b37ba..a5eef25 100644 --- a/ui/abc_render_a.c +++ b/ui/abc_render_a.c @@ -32,31 +32,6 @@ static GLuint texture_rgba = 0; static GLuint uniform_mvp; static GLuint uniform_rgba; -static int __width = 0; -static int __height = 0; - -static int __init_buffers(GLuint* vao, GLuint buffers[2]) -{ - glGenBuffers(2, buffers); - glBindBuffer(GL_ARRAY_BUFFER, buffers[0]); - glBufferData(GL_ARRAY_BUFFER, sizeof(vert_array), vert_array, GL_STATIC_DRAW); - glBindBuffer(GL_ARRAY_BUFFER, buffers[1]); - glBufferData(GL_ARRAY_BUFFER, sizeof(texture_array), texture_array, GL_STATIC_DRAW); - - glGenVertexArrays(1, vao); - glBindVertexArray(*vao); - - glBindBuffer(GL_ARRAY_BUFFER, buffers[0]); - glEnableVertexAttribArray(0); - glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, 0); - - glBindBuffer(GL_ARRAY_BUFFER, buffers[1]); - glEnableVertexAttribArray(1); - glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, 0); - - glBindVertexArray(0); - return 0; -} static int _render_fini_a(abc_render_t* render) { @@ -81,11 +56,11 @@ static int _render_draw_a(abc_render_t* render, abc_obj_t* obj, int width, int h scf_list_t* l; abc_obj_t* attr; - uint8_t* rgba = calloc(1, obj->w * obj->h * 4); - if (!rgba) + uint8_t* bgra = calloc(1, obj->w * obj->h * 4); + if (!bgra) return -ENOMEM; - surface = cairo_image_surface_create_for_data(rgba, CAIRO_FORMAT_ARGB32, obj->w, obj->h, obj->w * 4); + surface = cairo_image_surface_create_for_data(bgra, CAIRO_FORMAT_ARGB32, obj->w, obj->h, obj->w * 4); cr = cairo_create(surface); cairo_set_line_width(cr, 1); @@ -163,7 +138,7 @@ static int _render_draw_a(abc_render_t* render, abc_obj_t* obj, int width, int h // board glActiveTexture(GL_TEXTURE0); glBindTexture (GL_TEXTURE_2D, texture_rgba); - glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA, obj->w, obj->h, 0, GL_RGBA, GL_UNSIGNED_BYTE, rgba); + glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA, obj->w, obj->h, 0, GL_RGBA, GL_UNSIGNED_BYTE, bgra); glUniform1i(uniform_rgba, 0); // draw @@ -177,7 +152,7 @@ static int _render_draw_a(abc_render_t* render, abc_obj_t* obj, int width, int h glBindVertexArray(0); glUseProgram(0); - free(rgba); + free(bgra); return 0; } diff --git a/ui/abc_render_a_href.c b/ui/abc_render_a_href.c index 96365c0..4eaddf1 100644 --- a/ui/abc_render_a_href.c +++ b/ui/abc_render_a_href.c @@ -32,31 +32,6 @@ static GLuint texture_rgba = 0; static GLuint uniform_mvp; static GLuint uniform_rgba; -static int __width = 0; -static int __height = 0; - -static int __init_buffers(GLuint* vao, GLuint buffers[2]) -{ - glGenBuffers(2, buffers); - glBindBuffer(GL_ARRAY_BUFFER, buffers[0]); - glBufferData(GL_ARRAY_BUFFER, sizeof(vert_array), vert_array, GL_STATIC_DRAW); - glBindBuffer(GL_ARRAY_BUFFER, buffers[1]); - glBufferData(GL_ARRAY_BUFFER, sizeof(texture_array), texture_array, GL_STATIC_DRAW); - - glGenVertexArrays(1, vao); - glBindVertexArray(*vao); - - glBindBuffer(GL_ARRAY_BUFFER, buffers[0]); - glEnableVertexAttribArray(0); - glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, 0); - - glBindBuffer(GL_ARRAY_BUFFER, buffers[1]); - glEnableVertexAttribArray(1); - glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, 0); - - glBindVertexArray(0); - return 0; -} static int _render_fini_a_href(abc_render_t* render) { @@ -81,11 +56,11 @@ static int _render_draw_a_href(abc_render_t* render, abc_obj_t* obj, int width, scf_list_t* l; abc_obj_t* attr; - uint8_t* rgba = malloc(width * 32 * 4); - if (!rgba) + uint8_t* bgra = malloc(width * 32 * 4); + if (!bgra) return -ENOMEM; - surface = cairo_image_surface_create_for_data(rgba, CAIRO_FORMAT_ARGB32, width, 32, width * 4); + surface = cairo_image_surface_create_for_data(bgra, CAIRO_FORMAT_ARGB32, width, 32, width * 4); cr = cairo_create(surface); cairo_select_font_face(cr, "serif", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD); @@ -116,23 +91,23 @@ static int _render_draw_a_href(abc_render_t* render, abc_obj_t* obj, int width, if (l == scf_list_sentinel(&obj->attrs)) { scf_loge("hyper link '%s' not found a URL\n", obj->text->data); - free(rgba); - rgba = NULL; + free(bgra); + bgra = NULL; return -EINVAL; } scf_logd("extents: x_bearing: %f, width: %f, y_bearing: %f, height: %f\n", extents.x_bearing, extents.width, extents.y_bearing, extents.height); - void* p = realloc(rgba, w * h * 4); + void* p = realloc(bgra, w * h * 4); if (!p) { - free(rgba); - rgba = NULL; + free(bgra); + bgra = NULL; return -ENOMEM; } - rgba = p; + bgra = p; - surface = cairo_image_surface_create_for_data(rgba, CAIRO_FORMAT_ARGB32, w, h, w * 4); + surface = cairo_image_surface_create_for_data(bgra, CAIRO_FORMAT_ARGB32, w, h, w * 4); cr = cairo_create(surface); cairo_set_line_width(cr, 1); @@ -188,7 +163,7 @@ static int _render_draw_a_href(abc_render_t* render, abc_obj_t* obj, int width, // board glActiveTexture(GL_TEXTURE0); glBindTexture (GL_TEXTURE_2D, texture_rgba); - glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, rgba); + glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, bgra); glUniform1i(uniform_rgba, 0); // draw @@ -202,7 +177,7 @@ static int _render_draw_a_href(abc_render_t* render, abc_obj_t* obj, int width, glBindVertexArray(0); glUseProgram(0); - free(rgba); + free(bgra); return 0; } diff --git a/ui/abc_render_h1.c b/ui/abc_render_h1.c index 8a94b5c..db72fc2 100644 --- a/ui/abc_render_h1.c +++ b/ui/abc_render_h1.c @@ -32,31 +32,6 @@ static GLuint texture_rgba = 0; static GLuint uniform_mvp; static GLuint uniform_rgba; -static int __width = 0; -static int __height = 0; - -static int __init_buffers(GLuint* vao, GLuint buffers[2]) -{ - glGenBuffers(2, buffers); - glBindBuffer(GL_ARRAY_BUFFER, buffers[0]); - glBufferData(GL_ARRAY_BUFFER, sizeof(vert_array), vert_array, GL_STATIC_DRAW); - glBindBuffer(GL_ARRAY_BUFFER, buffers[1]); - glBufferData(GL_ARRAY_BUFFER, sizeof(texture_array), texture_array, GL_STATIC_DRAW); - - glGenVertexArrays(1, vao); - glBindVertexArray(*vao); - - glBindBuffer(GL_ARRAY_BUFFER, buffers[0]); - glEnableVertexAttribArray(0); - glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, 0); - - glBindBuffer(GL_ARRAY_BUFFER, buffers[1]); - glEnableVertexAttribArray(1); - glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, 0); - - glBindVertexArray(0); - return 0; -} static int _render_fini_h1(abc_render_t* render) { @@ -81,11 +56,11 @@ static int _render_draw_h1(abc_render_t* render, abc_obj_t* obj, int width, int scf_list_t* l; abc_obj_t* attr; - uint8_t* rgba = calloc(1, obj->w * obj->h * 4); - if (!rgba) + uint8_t* bgra = calloc(1, obj->w * obj->h * 4); + if (!bgra) return -ENOMEM; - surface = cairo_image_surface_create_for_data(rgba, CAIRO_FORMAT_ARGB32, obj->w, obj->h, obj->w * 4); + surface = cairo_image_surface_create_for_data(bgra, CAIRO_FORMAT_ARGB32, obj->w, obj->h, obj->w * 4); cr = cairo_create(surface); cairo_set_line_width(cr, 1); @@ -152,7 +127,7 @@ static int _render_draw_h1(abc_render_t* render, abc_obj_t* obj, int width, int // board glActiveTexture(GL_TEXTURE0); glBindTexture (GL_TEXTURE_2D, texture_rgba); - glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA, obj->w, obj->h, 0, GL_RGBA, GL_UNSIGNED_BYTE, rgba); + glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA, obj->w, obj->h, 0, GL_RGBA, GL_UNSIGNED_BYTE, bgra); glUniform1i(uniform_rgba, 0); // draw @@ -166,7 +141,7 @@ static int _render_draw_h1(abc_render_t* render, abc_obj_t* obj, int width, int glBindVertexArray(0); glUseProgram(0); - free(rgba); + free(bgra); return 0; } diff --git a/ui/abc_render_img.c b/ui/abc_render_img.c new file mode 100644 index 0000000..5e9feb7 --- /dev/null +++ b/ui/abc_render_img.c @@ -0,0 +1,140 @@ +#include"abc.h" +#include"abc_ffmpeg.h" + +static const char* vert_shader = + "#version 330 core\n" + "layout(location = 0) in vec4 position; \n" + "layout(location = 1) in vec2 a_texCoord; \n" + "out vec2 v_texCoord; \n" + "uniform mat4 mvp; \n" + "void main() { \n" + "gl_Position = mvp * position; \n" + "v_texCoord = a_texCoord; \n" + "} \n"; + +static const char* frag_shader = + "#version 330 core\n" + "in vec2 v_texCoord; \n" + "out vec4 outputColor; \n" + "uniform sampler2D tex_rgba; \n" + "void main() { \n" + " vec2 xy = v_texCoord; \n" + " vec4 v = texture2D(tex_rgba, xy).rgba; \n" + " outputColor = vec4(v.b, v.g, v.r, 1.0); \n" + "} \n"; + + +static GLuint program = 0; + +static GLuint vao = 0; +static GLuint buffers[2] = {0}; +static GLuint texture_rgba = 0; + +static GLuint uniform_mvp; +static GLuint uniform_rgba; + + +static int _render_fini_img(abc_render_t* render) +{ + return 0; +} + +static int _render_draw_img(abc_render_t* render, abc_obj_t* obj, int width, int height) +{ + scf_list_t* l; + abc_obj_t* attr; + abc_img_t* img = NULL; + + for (l = scf_list_head(&obj->attrs); l != scf_list_sentinel(&obj->attrs); l = scf_list_next(l)) { + attr = scf_list_data(l, abc_obj_t, list); + + if (ABC_HTML_ATTR_SRC == attr->type) + break; + } + + if (l == scf_list_sentinel(&obj->attrs)) { + scf_loge("src image of '%s' not found\n", obj->key->data); + return -1; + } + + int ret = abc_img_open(&img, attr->value->data); + if (ret < 0) + return ret; + + uint8_t* bgra = calloc(1, img->width * img->height * 4); + if (!bgra) { + abc_img_close(img); + return -ENOMEM; + } + + ret = abc_img_read(img, bgra, img->width * img->height * 4); + if (ret < 0) { + abc_img_close(img); + free(bgra); + return ret; + } + + if (0 == program) + __init_program(&program, vert_shader, frag_shader); + + if (0 == vao) + __init_buffers(&vao, buffers); + + if (0 == texture_rgba) + __init_texture(&texture_rgba, GL_RGBA, img->width, img->height, NULL); + + float mvp[16]; + __compute_mvp(mvp, 0, 0, 0); + + scf_logi("%s, x: %d, y: %d, w: %d, h: %d\n", obj->key->data, obj->x, obj->y, obj->w, obj->h); + + GLfloat vert_update[] = + { + 2.0 * obj->x / (float)width - 1.0, + -2.0 * (obj->y + obj->h) / (float)height + 1.0, + + 2.0 * (obj->x + obj->w) / (float)width - 1.0, + -2.0 * (obj->y + obj->h) / (float)height + 1.0, + + 2.0 * obj->x / (float)width - 1.0, + -2.0 * obj->y / (float)height + 1.0, + + 2.0 * (obj->x + obj->w) / (float)width - 1.0, + -2.0 * obj->y / (float)height + 1.0, + }; + + glUseProgram(program); + uniform_rgba = glGetUniformLocation(program, "tex_rgba"); + uniform_mvp = glGetUniformLocation(program, "mvp"); + + glUniformMatrix4fv(uniform_mvp, 1, GL_FALSE, mvp); + + // board + glActiveTexture(GL_TEXTURE0); + glBindTexture (GL_TEXTURE_2D, texture_rgba); + glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA, img->width, img->height, 0, GL_RGBA, GL_UNSIGNED_BYTE, bgra); + glUniform1i(uniform_rgba, 0); + + // draw + glBindBuffer (GL_ARRAY_BUFFER, buffers[0]); + glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vert_update), vert_update); + + glBindVertexArray(vao); + + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + + glBindVertexArray(0); + glUseProgram(0); + + abc_img_close(img); + free(bgra); + return 0; +} + +abc_render_t abc_render_img = +{ + .type = ABC_HTML_IMG, + + .draw = _render_draw_img, + .fini = _render_fini_img, +};