本文整理汇总了C++中clan::Canvas类的典型用法代码示例。如果您正苦于以下问题:C++ Canvas类的具体用法?C++ Canvas怎么用?C++ Canvas使用的例子?那么恭喜您, 这里精选的类代码示例或许可以为您提供帮助。
在下文中一共展示了Canvas类的20个代码示例,这些例子默认根据受欢迎程度排序。您可以为喜欢或者感觉有用的代码点赞,您的评价将有助于我们的系统推荐出更棒的C++代码示例。
示例1: go
void why::Application::draw_game_over(clan::Canvas &c)
{
using namespace boost;
using namespace std;
using namespace clan;
static const string go("GAME OVER");
static const string go2("Press Any Key To Continue");
static Font fbig = m_rc_manager->get_font(80);
float x = static_cast<float>(
((c.get_width() / 2.0f) - (fbig.get_text_size(c, go).width / 2.0f))
);
float y = c.get_height() / 2.0f;
draw_info_box(c);
fbig.draw_text(c, x, y, go);
static Font fsmall = m_rc_manager->get_font();
y += fbig.get_font_metrics().get_height();
x = static_cast<float>(
((c.get_width() / 2.0f) - (fsmall.get_text_size(c, go2).width / 2.0f))
);
fsmall.draw_text(c, x, y, go2);
}
开发者ID:vdell,项目名称:inertia,代码行数:27,代码来源:why_app.cpp
示例2: render_bloom_combine
void App::render_bloom_combine(clan::Canvas &canvas, clan::Texture2D &tex_base, clan::Texture2D &tex_bloom, clan::ProgramObject &program_object)
{
canvas.flush();
clan::GraphicContext gc = canvas.get_gc();
gc.set_texture(0, tex_base);
gc.set_texture(1, tex_bloom);
gc.set_program_object(program_object);
program_object.set_uniform1i(("BaseTexture"), 0);
program_object.set_uniform1f(("BaseIntensity"), base_intensity);
program_object.set_uniform1f(("BaseSaturation"), base_saturation);
program_object.set_uniform1i(("BloomTexture"), 1);
program_object.set_uniform1f(("BloomIntensity"), bloom_intensity);
program_object.set_uniform1f(("BloomSaturation"), bloom_saturation);
program_object.set_uniform_matrix("cl_ModelViewProjectionMatrix", canvas.get_projection() * canvas.get_transform());
draw_texture(gc, clan::Rectf(0,0,canvas.get_width(),canvas.get_height()), clan::Rectf(0.0f, 0.0f, 1.0f, 1.0f));
gc.reset_program_object();
gc.reset_texture(0);
gc.reset_texture(1);
}
开发者ID:keigen-shu,项目名称:ClanLib,代码行数:26,代码来源:app.cpp
示例3: set_stars
void Timing::set_stars(clan::Canvas &canvas, int star_cnt)
{
stars.clear();
stars.resize(star_cnt);
unsigned int random = 1231;
int gc_width = canvas.get_width();
int gc_height = canvas.get_height();
for (int cnt=0; cnt < star_cnt; cnt++)
{
stars[cnt].xpos = (float) (random % gc_width);
random+= 143222321;
stars[cnt].ypos = (float) (random % gc_height);
random+= 89079086;
stars[cnt].speed = (((float) (random % 256)) ) + 10.0f;
random*= 595443965;
stars[cnt].color.r = (((float) (random % 256)) / 256.0f);
random*= 196243625;
stars[cnt].color.b = (((float) (random % 256)) / 256.0f);
random*= 14365;
stars[cnt].color.g = (((float) (random % 256)) / 256.0f);
stars[cnt].color.a = 1.0f;
}
}
开发者ID:doughdemon,项目名称:ClanLib,代码行数:26,代码来源:timing.cpp
示例4: set_user_projection
void App::set_user_projection(clan::Canvas &canvas, clan::Sizef &area_size, Options *options)
{
canvas.get_gc().set_viewport(clan::Rectf(0, 0, area_size));
float lens_zoom = 3.2f;
float lens_near = 0.1f;
float lens_far = 10000.0f;
float lens_aspect = 1.0f;
float fov = 2.0f * atan2(1.0f, lens_zoom);
float aspect = 1.0f;
aspect = ( area_size.width * lens_aspect) / area_size.height;
fov = (fov * 180.0f) / clan::PI;
clan::Mat4f projection_matrix = clan::Mat4f::perspective( fov, aspect, lens_near, lens_far, clan::handed_left, clan::clip_negative_positive_w);
canvas.set_projection(projection_matrix);
clan::Mat4f modelview_matrix = clan::Mat4f::identity();
modelview_matrix.translate_self(-1.0f, 1.0, lens_zoom);
modelview_matrix = modelview_matrix * clan::Mat4f::rotate(clan::Angle((float) -options->grid_angle, clan::angle_degrees), 1.0f, 0.0f, 0.0f, false);
modelview_matrix.scale_self(2.0f / area_size.width, -2.0f / area_size.height, 1.0f);
canvas.set_modelview(modelview_matrix);
}
开发者ID:finalJ2,项目名称:ClanLib,代码行数:26,代码来源:app.cpp
示例5: on_render
void GridComponent::on_render(clan::Canvas &canvas, const clan::Rect &update_rect)
{
set_cliprect(canvas, get_size());
clan::Rect g = get_geometry().get_size();
bool tab_parent = (get_parent_component()->get_tag_name() == "tabpage");
if (tab_parent)
{
canvas.fill_rect( g, clan::Colorf::whitesmoke);
}
else
{
//canvas.fill_rect( g, clan::Colorf::darkgray);
canvas.fill_rect( g, clan::Colorf(199/255.0f, 209/255.0f, 224/255.0f));
canvas.fill_rect( boundary, clan::Colorf::lightgrey/*clan::Colorf("E0DFE3")*/);
}
/*
if (!tab_parent)
{
clan::Draw::line(canvas, (float)boundary.left, (float)boundary.bottom, (float)boundary.right, (float)boundary.bottom, clan::Colorf::black);
clan::Draw::line(canvas, (float)boundary.right, (float)boundary.top, (float)boundary.right, (float)boundary.bottom, clan::Colorf::black);
// canvas.fill_rect( get_boundary_grabber_se(), clan::Colorf::darkslategray);
}
*/
clan::Rect framebox = part_windowframe.get_content_box(boundary);
framebox.translate(-framebox.left, -framebox.top);
part_windowframe.render_box(canvas, framebox);
reset_cliprect(canvas);
}
开发者ID:Cassie90,项目名称:ClanLib,代码行数:31,代码来源:grid_component.cpp
示例6: linec
void why::Application::draw_info_box(clan::Canvas &c)
{
c.fill_rect(m_world_area, clan::Colorf(0.0f, 0.0f, 0.0f, 0.6f));
static clan:: Colorf linec(clan::Colorf::white);
linec.set_alpha(0.3f);
c.draw_box(m_world_area, linec);
}
开发者ID:vdell,项目名称:inertia,代码行数:8,代码来源:why_app.cpp
示例7: get_stencil
clan::Image App::get_stencil(clan::Canvas &canvas, clan::Rect rect)
{
canvas.flush();
// For an unknown reason, stencil reads should be a multiple of 32
rect.left = 32 * ((rect.left + 31) / 32);
rect.top = 32 * ((rect.top + 31) / 32);
rect.right = 32 * ((rect.right + 31) / 32);
rect.bottom = 32 * ((rect.bottom + 31) / 32);
int rect_width = rect.get_width();
int rect_height = rect.get_height();
std::vector<unsigned char> buffer;
buffer.resize(rect_width * rect_height);
glPixelStorei(GL_PACK_ALIGNMENT, 1);
glPixelStorei(GL_PACK_ROW_LENGTH, rect_width);
glPixelStorei(GL_PACK_SKIP_PIXELS, 0);
glPixelStorei(GL_PACK_SKIP_ROWS, 0);
glReadBuffer(GL_BACK);
if (glClampColor)
{
#ifdef GL_CLAMP_READ_COLOR
glClampColor(GL_CLAMP_READ_COLOR, GL_FALSE);
#else
glClampColor(clan::GL_CLAMP_READ_COLOR, GL_FALSE);
#endif
}
glReadPixels(rect.left, canvas.get_height()- rect.bottom, rect_width, rect_height, GL_STENCIL_INDEX, GL_UNSIGNED_BYTE, &buffer[0]);
clan::PixelBuffer pbuf(rect_width, rect_height, clan::tf_rgba8);
unsigned int *pdata = (unsigned int *) pbuf.get_data();
unsigned char *rdata = &buffer[0];
for (int ycnt=0; ycnt < rect_height; ycnt++)
{
for (int xcnt=0; xcnt < rect_width; xcnt++)
{
int value = *(rdata++);
if (value == 0)
{
*(pdata++) = 0xFF005500;
}
else
{
value = value * 16;
value = 0xFF000000 | value | (value << 8) | (value << 16);
*(pdata++) = value;
}
}
}
pbuf.flip_vertical();
return clan::Image(canvas, pbuf, pbuf.get_size());
}
开发者ID:ArtHome12,项目名称:ClanLib,代码行数:55,代码来源:app.cpp
示例8: draw
void Text::draw(clan::Canvas &canvas, const clan::Rect &rect)
{
int out_draw_offset;
std::string text = build_text(canvas, rect.get_width(), scroller_xoffset, out_draw_offset);
int ypos = rect.bottom - ((rect.get_height() - font_metrics.get_ascent())/2);
// Remove the next line to observe how the clipping works
canvas.set_cliprect(rect);
font.draw_text(canvas, rect.left - out_draw_offset, ypos, text);
canvas.reset_cliprect();
}
开发者ID:punkkeks,项目名称:ClanLib,代码行数:12,代码来源:text.cpp
示例9: on_render
void ColorWheel::on_render(clan::Canvas &canvas, const clan::Rect &update_rect)
{
get_options();
clan::Pointf center( (float) canvas.get_width()/2.0f, (float) canvas.get_height()/2.0f);
float radius = 200.0f;
create_colorwheel(center, radius);
canvas.fill_triangles(colorwheel_positions, colorwheel_colors, colorwheel_segments * 3);
draw_labels(canvas);
}
开发者ID:punkkeks,项目名称:ClanLib,代码行数:12,代码来源:colorwheel.cpp
示例10: ver
void why::Application::draw_main_menu(clan::Canvas &c)
{
using namespace clan;
m_main_menu->draw(c);
const std::string ver (std::string(INERTIA_VERSION) + "v");
Font f = m_rc_manager->get_font();
Pointf vpos;
vpos.x = c.get_width() - (ver.length() * f.get_font_metrics().get_average_character_width() + 10.0f);
vpos.y = c.get_height() - 10.0f;
f.draw_text(c, vpos, ver);
}
开发者ID:vdell,项目名称:inertia,代码行数:14,代码来源:why_app.cpp
示例11: draw_demo
void SineScroll::draw_demo(clan::Canvas &canvas, int delta_ms)
{
clan::Rectf rect(0.0f, 0.0f, clan::Sizef(300.0f, 300.0f));
clan::Rectf texture_unit1_coords(0.0f, 0.0f, 1.0f, 1.0f);
std::vector<clan::Vec2f> dest_position;
std::vector<clan::Vec2f> texture_position;
int dest_width = canvas.get_width();
if (dest_width <=0)
return;
int dest_xoffset = 0;
int gc_height = canvas.get_height();
int dest_height = 128;
int dest_start_y = (gc_height - dest_height) / 2;
float texture_y_start = 0.15f; // Set to 0.0f for start and 1.0f for end to use the entire texture
float texture_y_end = 0.5f;
dest_position.reserve(dest_width * 2);
texture_position.reserve(dest_width * 2);
float sin_amplitude = ( (float) gc_height / 4.0f);
if (delta_ms > 1000) // Limit to 1 second to frame
delta_ms = 1000;
sin_offset += ((float) delta_ms / 1000.0f);
if (sin_offset > (2.0f * clan::PI))
sin_offset -= clan::PI * 2.0f;
for (int cnt=0; cnt < dest_width; cnt++)
{
float y_offset = sin_amplitude * sin( sin_offset + (float) cnt / 100.0f ) ;
dest_position.push_back( clan::Vec2f( cnt, dest_start_y + y_offset ) );
dest_position.push_back( clan::Vec2f( cnt, dest_start_y + dest_height + y_offset) );
texture_position.push_back( clan::Vec2f( (float) cnt / dest_width, texture_y_start ) );
texture_position.push_back( clan::Vec2f( (float) cnt / dest_width, texture_y_end ) );
}
canvas.draw_lines(&dest_position[0], &texture_position[0], dest_position.size(), texture);
}
开发者ID:keigen-shu,项目名称:ClanLib,代码行数:49,代码来源:sinescroll.cpp
示例12: draw_section
void Alpha::draw_section(clan::Canvas &canvas, clan::Font &font, int yoffset, const clan::Colorf &background, const clan::Colorf &vertex_colour, const clan::Colorf &image_colour)
{
// Draw the background without blending to set the specified RGBA
canvas.set_blend_state(blend_disabled);
const int outer_area_size = 32;
const int outer_xoffset = 8;
canvas.fill_rect( outer_xoffset, yoffset, outer_xoffset + outer_area_size, yoffset + outer_area_size, background);
canvas.set_blend_state(blend_enabled);
// Create the image
clan::Image image = create_block(canvas, image_colour);
// Draw the image
image.set_color(vertex_colour);
image.draw(canvas, outer_xoffset + (outer_area_size - image.get_width())/2, yoffset + (outer_area_size - image.get_height())/2);
// Get the composited pixel buffer
clan::Rect rect(outer_xoffset + outer_area_size / 2, (yoffset + outer_area_size / 2), clan::Size(64,64));
clan::PixelBuffer pbuff = canvas.get_pixeldata(rect, clan::tf_rgba8);
pbuff.lock(canvas, clan::access_read_only);
clan::ImageProviderFactory::save(pbuff, "test.png");
clan::Colorf output = pbuff.get_pixel(0,0);
pbuff.unlock();
// Create the information string
std::string info(clan::string_format("Initial Destination Colour: RGBA = %1, %2, %3, %4", background.r , background.g, background.b, background.a));
int xpos = outer_xoffset + outer_area_size + 8;
int ypos = yoffset - 4;
font.draw_text(canvas, xpos, ypos, info, clan::Colorf::black);
info = std::string(clan::string_format("Vertex Colour: RGBA = %1, %2, %3, %4", vertex_colour.r , vertex_colour.g, vertex_colour.b, vertex_colour.a));
ypos += 16;
font.draw_text(canvas, xpos, ypos, info, clan::Colorf::black);
info = std::string(clan::string_format("Image Colour: RGBA = %1, %2, %3, %4", image_colour.r , image_colour.g, image_colour.b, image_colour.a));
ypos += 16;
font.draw_text(canvas, xpos, ypos, info, clan::Colorf::black);
info = std::string(clan::string_format("Destination Colour: RGBA = %1, %2, %3, %4", output.r , output.g, output.b, output.a));
ypos += 16;
font.draw_text(canvas, xpos, ypos, info, clan::Colorf::black);
}
开发者ID:Cassie90,项目名称:ClanLib,代码行数:48,代码来源:alpha.cpp
示例13: draw_graphics
void Timing::draw_graphics(clan::Canvas &canvas, float time_delta)
{
int gc_width = canvas.get_width();
std::vector<Star>::size_type max, cnt;
max = stars.size();
for (cnt=0; cnt<max; cnt++)
{
float xpos = stars[cnt].xpos;
xpos += time_delta * stars[cnt].speed;
if (xpos >= gc_width)
xpos -= (gc_width + 8);
stars[cnt].xpos = xpos;
canvas.fill_circle(xpos, stars[cnt].ypos, 6.0f, stars[cnt].color);
}
}
开发者ID:doughdemon,项目名称:ClanLib,代码行数:16,代码来源:timing.cpp
示例14: draw_text
void TextFade::draw_text(clan::Canvas &canvas, clan::Font &font, int ypos, const char *text)
{
// For this example, to keep things simple, we only handle ASCII characters
int gc_width = canvas.get_width();
clan::Size text_size = clan::Size(font.measure_text(canvas, text).bbox_size);
int xpos = (gc_width - text_size.width) / 2;
while(*text)
{
char let = *(text++);
char buffer[2];
buffer[0] = let;
buffer[1] = 0;
int position_off_centre = (gc_width/2) - xpos;
if (position_off_centre < 0)
position_off_centre = -position_off_centre;
float alpha = 1.0f - ( (float) position_off_centre * 2.0f / gc_width );
if (alpha > 0.0f)
font.draw_text(canvas, xpos, ypos, buffer, clan::Colorf(0.4f, 0.4f, 1.0f, alpha));
xpos += font.get_metrics(canvas, let).bbox_size.width;
}
}
开发者ID:ARMCoderCHS,项目名称:ClanLib,代码行数:28,代码来源:textfade.cpp
示例15: on_render_overlay
void GridComponent::on_render_overlay(clan::Canvas &canvas, const clan::Rect &update_rect)
{
set_cliprect(canvas, get_size());
std::vector<GridObject *> selection = main_window->get_selection()->get_selection();
for (size_t i = 0; i < selection.size(); i++)
{
clan::Rect grabbers[8] =
{
selection[i]->get_grabber_e(),
selection[i]->get_grabber_se(),
selection[i]->get_grabber_s(),
selection[i]->get_grabber_sw(),
selection[i]->get_grabber_w(),
selection[i]->get_grabber_nw(),
selection[i]->get_grabber_n(),
selection[i]->get_grabber_ne()
};
for (int j=0; j<8; j++)
grabbers[j] = window_to_component_coords(selection[i]->component_to_window_coords(grabbers[j]));
clan::Rect pos = window_to_component_coords(selection[i]->component_to_window_coords(selection[i]->get_size()));
pos.expand(4,4,3,3);
canvas.draw_box( pos, clan::Colorf(100.0f/255.0f, 100.0f/255.0f, 100.0f/255.0f, 0.25f));
for (int j=0; j<8; j++)
{
canvas.fill_rect( grabbers[j], clan::Colorf::white);
canvas.draw_box( grabbers[j], clan::Colorf::black);
}
}
if (netselect_box.get_size() != clan::Size(0,0))
{
clan::Rect box = netselect_box;
box.translate(component_container->get_geometry().left, component_container->get_geometry().top);
clan::Colorf c = clan::Colorf::blue;
c.set_alpha(0.1f);
canvas.fill_rect( box, c);
canvas.draw_box( box, clan::Colorf::blue);
}
reset_cliprect(canvas);
}
开发者ID:Cassie90,项目名称:ClanLib,代码行数:45,代码来源:grid_component.cpp
示例16: render_extract_highlights
void App::render_extract_highlights(clan::Canvas &canvas, clan::Texture2D &source_texture, clan::ProgramObject &program_object)
{
canvas.flush();
clan::GraphicContext gc = canvas.get_gc();
gc.set_texture(0, source_texture);
gc.set_program_object(program_object);
program_object.set_uniform1i(("SourceTexture"), 0);
program_object.set_uniform1f(("Threshold"), highlight_threshold);
program_object.set_uniform_matrix("cl_ModelViewProjectionMatrix", canvas.get_projection() * canvas.get_transform());
draw_texture(gc, clan::Rectf(0,0,canvas.get_width(),canvas.get_height()), clan::Rectf(0.0f, 0.0f, 1.0f, 1.0f));
gc.reset_program_object();
gc.reset_texture(0);
}
开发者ID:keigen-shu,项目名称:ClanLib,代码行数:19,代码来源:app.cpp
示例17: screen_width
void why::Application::draw_background(clan::Canvas &c, bool tile)
{
using namespace clan;
Sprite *bg = nullptr;
if (GameState::is_active(GameStateValue::Menu))
{
bg = &m_menu_bg_sprite;
}
else
{
bg = &m_game_bg_sprite;
}
const float screen_width(static_cast<float>(c.get_width()));
const float screen_height(static_cast<float>(c.get_height()));
const float sprite_width(static_cast<float>(bg->get_width()));
const float sprite_height(static_cast<float>(bg->get_height()));
if (tile)
{
float x = 0, y = 0;
while (y < screen_height + sprite_height)
{
bg->draw(c, x, y);
x += sprite_width;
if (x > screen_width + sprite_width)
{
y += sprite_height;
x = 0.0f;
}
}
}
else
{
bg->draw(c, Rectf(0.0f, 0.0f, sprite_width, sprite_height),
Rectf(0.0f, 0.0f, screen_width, screen_height));
}
}
开发者ID:vdell,项目名称:inertia,代码行数:41,代码来源:why_app.cpp
示例18: render
void Note_Single::render(UI::Tracker const &tracker, clan::Canvas &canvas) const
{
if (this->getScore().rank != EJRank::NONE) return;
rectf p = tracker.getNoteRect(this->getKey(), this->getTick());
if (p.left > tracker.get_width () || p.right < 0)
return;
if (p.top > tracker.get_height())
return;
p.top = tracker.get_height() - p.top;
p.bottom = tracker.get_height() - p.bottom;
// Clip note to edge of tracker
if (p.bottom > tracker.get_height()) {
p.top = tracker.get_height() - std::abs(p.bottom - p.top);
p.bottom = tracker.get_height();
}
clan::Colorf color;
switch (getKey())
{
case ENKey::NOTE_P1_1:
case ENKey::NOTE_P1_3:
case ENKey::NOTE_P1_5:
case ENKey::NOTE_P1_7:
color = clan::Colorf::white;
break;
case ENKey::NOTE_P1_2:
case ENKey::NOTE_P1_6:
color = clan::Colorf::cyan;
break;
case ENKey::NOTE_P1_4:
color = clan::Colorf::gold;
break;
default:
color = clan::Colorf::white;
}
canvas.fill_rect(p, color);
}
开发者ID:keigen-shu,项目名称:LostWave,代码行数:43,代码来源:Note.cpp
示例19: render_gaussian_blur
void App::render_gaussian_blur(clan::Canvas &canvas, float blur_amount, clan::Texture2D &source_texture, clan::ProgramObject &program_object, float dx, float dy)
{
uniforms.sample[0].weight = compute_gaussian(0, blur_amount);
uniforms.sample[0].offset_x = 0.0f;
uniforms.sample[0].offset_y = 0.0f;
float totalWeights = uniforms.sample[0].weight;
for (int i = 0; i < sampleCount / 2; i++)
{
float weight = compute_gaussian(i + 1.0f, blur_amount);
uniforms.sample[i * 2 + 1].weight = weight;
uniforms.sample[i * 2 + 2].weight = weight;
totalWeights += weight * 2;
float sampleOffset = i * 2 + 1.5f;
clan::Vec2f delta(dx * sampleOffset, dy * sampleOffset);
uniforms.sample[i * 2 + 1].offset_x = delta.x;
uniforms.sample[i * 2 + 1].offset_y = delta.y;
uniforms.sample[i * 2 + 2].offset_x = -delta.x;
uniforms.sample[i * 2 + 2].offset_y = -delta.y;
}
for (int i = 0; i < sampleCount; i++)
{
uniforms.sample[i].weight /= totalWeights;
}
canvas.flush();
clan::GraphicContext gc = canvas.get_gc();
gc.set_texture(0, source_texture);
gc.set_program_object(program_object);
uniforms.cl_ModelViewProjectionMatrix = canvas.get_projection() * canvas.get_transform();
gpu_uniforms.upload_data(gc, &uniforms, 1);
gc.set_uniform_buffer(0, gpu_uniforms);
draw_texture(gc, clan::Rectf(0,0,canvas.get_width(),canvas.get_height()), clan::Rectf(0.0f, 0.0f, 1.0f, 1.0f));
gc.reset_program_object();
gc.reset_texture(0);
}
开发者ID:doughdemon,项目名称:ClanLib,代码行数:48,代码来源:app.cpp
示例20: render_shockwave
void App::render_shockwave(clan::Canvas &canvas, clan::Texture2D &source_texture, clan::ProgramObject &program_object)
{
canvas.flush();
clan::GraphicContext gc = canvas.get_gc();
gc.set_texture(0, source_texture);
gc.set_program_object(program_object);
uniforms.cl_ModelViewProjectionMatrix = canvas.get_projection() * canvas.get_modelview();
gpu_uniforms.upload_data(gc, &uniforms, 1);
gc.set_uniform_buffer(0, gpu_uniforms);
draw_texture(gc, clan::Rectf(0,0,canvas.get_width(),canvas.get_height()), clan::Rectf(0.0f, 0.0f, 1.0f, 1.0f));
gc.reset_program_object();
gc.reset_texture(0);
}
开发者ID:finalJ2,项目名称:ClanLib,代码行数:17,代码来源:app.cpp
注:本文中的clan::Canvas类示例由纯净天空整理自Github/MSDocs等源码及文档管理平台,相关代码片段筛选自各路编程大神贡献的开源项目,源码版权归原作者所有,传播和使用请参考对应项目的License;未经允许,请勿转载。 |
请发表评论