Пример #1
0
	void EntitiesEditor::onInput(const InputState &state) {
		auto mouse_pos = state.mousePos() - clippedRect().min;
		computeCursor(mouse_pos, mouse_pos, state.isKeyPressed(InputKey::lshift));

		if(state.isKeyDown('s')) {
			m_mode = Mode::selecting;
			sendEvent(this, Event::button_clicked, m_mode);
		}
		if(state.isKeyDown('p')) {
			m_mode = Mode::placing;
			sendEvent(this, Event::button_clicked, m_mode);
		}

		if(m_proto) {
			int inc = 0;
			if(state.isKeyDown(InputKey::left)) inc = -1;
			if(state.isKeyDown(InputKey::right)) inc = 1;
			int dir_count = m_proto->sprite().dirCount(0);

			if(inc && dir_count)
				m_proto_angle = (m_proto_angle + inc + dir_count) % dir_count;
			m_proto->setDirAngle(constant::pi * 2.0f * (float)m_proto_angle / float(dir_count));
		}

		if(state.isKeyPressed(InputKey::del)) {
			for(int i = 0; i < (int)m_selected_ids.size(); i++)
				m_entity_map.remove(m_selected_ids[i]);
			m_selected_ids.clear();
		}

		m_view.update(state);
	}
Пример #2
0
void RenderRegion::repaintFlowThreadContentRectangle(const LayoutRect& repaintRect, const LayoutRect& flowThreadPortionRect, const LayoutPoint& regionLocation, const LayoutRect* flowThreadPortionClipRect)
{
    ASSERT(isValid());

    // We only have to issue a repaint in this region if the region rect intersects the repaint rect.
    LayoutRect clippedRect(repaintRect);

    if (flowThreadPortionClipRect) {
        LayoutRect flippedFlowThreadPortionClipRect(*flowThreadPortionClipRect);
        flowThread()->flipForWritingMode(flippedFlowThreadPortionClipRect);
        clippedRect.intersect(flippedFlowThreadPortionClipRect);
    }

    if (clippedRect.isEmpty())
        return;

    LayoutRect flippedFlowThreadPortionRect(flowThreadPortionRect);
    flowThread()->flipForWritingMode(flippedFlowThreadPortionRect); // Put the region rects into physical coordinates.

    // Put the region rect into the region's physical coordinate space.
    clippedRect.setLocation(regionLocation + (clippedRect.location() - flippedFlowThreadPortionRect.location()));

    // Now switch to the region's writing mode coordinate space and let it repaint itself.
    flipForWritingMode(clippedRect);
    
    // Issue the repaint.
    repaintRectangle(clippedRect);
}
Пример #3
0
void RenderFlowThread::repaintRectangleInRegions(const LayoutRect& repaintRect, bool immediate)
{
    if (!shouldRepaint(repaintRect) || !hasValidRegionInfo())
        return;

    for (RenderRegionList::iterator iter = m_regionList.begin(); iter != m_regionList.end(); ++iter) {
        RenderRegion* region = *iter;
        if (!region->isValid())
            continue;

        // We only have to issue a repaint in this region if the region rect intersects the repaint rect.
        LayoutRect flippedRegionRect(region->regionRect());
        LayoutRect flippedRegionOverflowRect(region->regionOverflowRect());
        flipForWritingMode(flippedRegionRect); // Put the region rects into physical coordinates.
        flipForWritingMode(flippedRegionOverflowRect);

        LayoutRect clippedRect(repaintRect);
        clippedRect.intersect(flippedRegionOverflowRect);
        if (clippedRect.isEmpty())
            continue;

        // Put the region rect into the region's physical coordinate space.
        clippedRect.setLocation(region->contentBoxRect().location() + (clippedRect.location() - flippedRegionRect.location()));

        // Now switch to the region's writing mode coordinate space and let it repaint itself.
        region->flipForWritingMode(clippedRect);
        LayoutStateDisabler layoutStateDisabler(view()); // We can't use layout state to repaint, since the region is somewhere else.

        // Can't use currentFlowThread as it possible to have imbricated flow threads and the wrong one could be used,
        // so, we let each region figure out the proper enclosing flow thread
        CurrentRenderFlowThreadDisabler disabler(view());
        region->repaintRectangle(clippedRect, immediate);
    }
}
Пример #4
0
	void TileSelector::drawContents(Renderer2D &out) const {
		int2 offset = innerOffset();
		IRect clip_rect(int2(0, 0), clippedRect().size());

		for(int n = 0; n < (int)m_tile_list.size(); n++) {
			const Tile *tile = m_tile_list[n].tile;
			IRect tile_rect = tile->rect();
			int2 pos = m_tile_list[n].pos - tile_rect.min - offset;

			if(areOverlapping(clip_rect, tile_rect + pos))
				tile->draw(out, pos);
		}
		
		if(m_selection) {
			int2 pos = m_selection->pos - offset;

			out.setViewPos(-clippedRect().min - pos + m_selection->tile->rect().min);
			IBox box(int3(0, 0, 0), m_selection->tile->bboxSize());
			drawBBox(out, box);
		//	out.addFilledRect(IRect(pos, pos + m_selection->size));
		}
	}
Пример #5
0
bool LayerAndroid::canUpdateWithBlit()
{
    if (!m_content || !m_scale)
        return false;
    IntRect clip = clippedRect();
    IntRect dirty = m_dirtyRegion.getBounds();
    dirty.intersect(clip);
    PrerenderedInval* prerendered = m_content->prerenderForRect(dirty);
    if (!prerendered)
        return false;
    // Check that the scales are "close enough" to produce the same rects
    FloatRect screenArea = prerendered->screenArea;
    screenArea.scale(1 / m_scale);
    IntRect enclosingDocArea = enclosingIntRect(screenArea);
    return enclosingDocArea == prerendered->area;
}
Пример #6
0
	GroupEditor::GroupEditor(IRect rect)
		:ui::Window(rect, Color(0, 0, 0)), m_tile_list(rect.width(), 2) {
		m_view = clippedRect();

		m_tile_group = nullptr;
		m_current_entry = nullptr;

		m_font = res::getFont(WindowStyle::fonts[1]);
		m_mode = mAddRemove;
		memset(m_offset, 0, sizeof(m_offset));
		m_selected_group_id = 0;
		m_selected_surface_id = -1;
		m_select_mode = 0;
		m_selection_mode = 0;
		m_tile_filter = TileFilter::floors;

		updateSelector();
	}
Пример #7
0
//! draws some text and clips it to the specified rectangle if wanted
void CGUIFont::draw(const wchar_t* text, const core::rect<s32>& position, video::SColor color, bool hcenter, bool vcenter, const core::rect<s32>* clip)
{
	if (!Driver)
		return;

	core::dimension2d<s32> textDimension;
	core::position2d<s32> offset = position.UpperLeftCorner;
	core::rect<s32> pos;

	if (hcenter || vcenter || clip)
		textDimension = getDimension(text);

	if (hcenter)
		offset.X = ((position.getWidth() - textDimension.Width)>>1) + offset.X;

	if (vcenter)
		offset.Y = ((position.getHeight() - textDimension.Height)>>1) + offset.Y;

	if (clip)
	{
		core::rect<s32> clippedRect(offset, textDimension);
		clippedRect.clipAgainst(*clip);
		if (!clippedRect.isValid())
			return;
	}

	while(*text)
	{
		SFontArea& area = Areas[getAreaFromCharacter(*text)];

		offset.X += area.underhang;

		SpriteBank->draw2DSprite(area.spriteno, offset, clip, color);

		offset.X += area.width + area.overhang + GlobalKerningWidth;

		++text;
	}
}
Пример #8
0
	bool ComboBox::onEvent(const Event &ev) {
		if(ev.type == Event::window_closed && ev.source == m_popup.get()) {
			m_dummy->selectEntry(m_popup->selectedId());
			m_popup = nullptr;
			updateButton();
			
			if(ev.value)
				sendEvent(this, Event::element_selected, m_dummy->selectedId());
		}
		else if(ev.type == Event::button_clicked && ev.source == m_button.get()) {
			DASSERT(!m_popup);

			if(m_drop_size > 0 && size()) {
				int popup_size = min(m_drop_size, m_dummy->size() * m_dummy->lineHeight());
				IRect clip_rect = clippedRect();
				IRect rect(clip_rect.min, int2(clip_rect.max.x, clip_rect.min.y + popup_size));

				m_popup = make_shared<ListBox>(rect, WindowStyle::gui_popup);
				for(int n = 0; n < size(); n++) {
					const ListBox::Entry &entry = (*m_dummy)[n];
					m_popup->addEntry(entry.text.c_str(), entry.color);
				}
				m_popup->selectEntry(m_dummy->selectedId());
				m_popup->setInnerOffset(int2(0, m_dummy->selectedId() * m_dummy->lineHeight()));
				mainWindow()->attach(m_popup, true);
			}
			else if(size() > 1) {
				int next_id = (selectedId() + 1) % size();
				selectEntry(next_id);
				sendEvent(this, Event::element_selected, next_id);
			}
		}
		else
			return false;

		return true;
	}
void RenderMultiColumnSet::repaintFlowThreadContent(const LayoutRect& repaintRect, bool immediate) const
{
    // Figure out the start and end columns and only check within that range so that we don't walk the
    // entire column set. Put the repaint rect into flow thread coordinates by flipping it first.
    LayoutRect flowThreadRepaintRect(repaintRect);
    flowThread()->flipForWritingMode(flowThreadRepaintRect);
    
    // Now we can compare this rect with the flow thread portions owned by each column. First let's
    // just see if the repaint rect intersects our flow thread portion at all.
    LayoutRect clippedRect(flowThreadRepaintRect);
    clippedRect.intersect(RenderRegion::flowThreadPortionOverflowRect());
    if (clippedRect.isEmpty())
        return;
    
    // Now we know we intersect at least one column. Let's figure out the logical top and logical
    // bottom of the area we're repainting.
    LayoutUnit repaintLogicalTop = isHorizontalWritingMode() ? flowThreadRepaintRect.y() : flowThreadRepaintRect.x();
    LayoutUnit repaintLogicalBottom = (isHorizontalWritingMode() ? flowThreadRepaintRect.maxY() : flowThreadRepaintRect.maxX()) - 1;
    
    unsigned startColumn = columnIndexAtOffset(repaintLogicalTop);
    unsigned endColumn = columnIndexAtOffset(repaintLogicalBottom);
    
    LayoutUnit colGap = columnGap();
    unsigned colCount = columnCount();
    for (unsigned i = startColumn; i <= endColumn; i++) {
        LayoutRect colRect = columnRectAt(i);
        
        // Get the portion of the flow thread that corresponds to this column.
        LayoutRect flowThreadPortion = flowThreadPortionRectAt(i);
        
        // Now get the overflow rect that corresponds to the column.
        LayoutRect flowThreadOverflowPortion = flowThreadPortionOverflowRect(flowThreadPortion, i, colCount, colGap);

        // Do a repaint for this specific column.
        repaintFlowThreadContentRectangle(repaintRect, immediate, flowThreadPortion, flowThreadOverflowPortion, colRect.location());
    }
}
Пример #10
0
//! draws some text and clips it to the specified rectangle if wanted
void ScalableFont::doDraw(const core::stringw& text,
                          const core::rect<s32>& position, video::SColor color,
                          bool hcenter, bool vcenter,
                          const core::rect<s32>* clip,
                          FontCharCollector* charCollector)
{
    if (!Driver) return;

    if (m_shadow)
    {
        m_shadow = false; // avoid infinite recursion

        core::rect<s32> shadowpos = position;
        shadowpos.LowerRightCorner.X += 2;
        shadowpos.LowerRightCorner.Y += 2;

        draw(text, shadowpos, m_shadow_color, hcenter, vcenter, clip);

        m_shadow = true; // set back
    }

    core::position2d<s32> offset = position.UpperLeftCorner;
    core::dimension2d<s32> text_dimension;

    if (m_rtl || hcenter || vcenter || clip)
    {
        text_dimension = getDimension(text.c_str());

        if (hcenter)    offset.X += (position.getWidth() - text_dimension.Width) / 2;
        else if (m_rtl) offset.X += (position.getWidth() - text_dimension.Width);

        if (vcenter)    offset.Y += (position.getHeight() - text_dimension.Height) / 2;
        if (clip)
        {
            core::rect<s32> clippedRect(offset, text_dimension);
            clippedRect.clipAgainst(*clip);
            if (!clippedRect.isValid()) return;
        }
    }

    // ---- collect character locations
    const unsigned int text_size = text.size();
    core::array<s32>               indices(text_size);
    core::array<core::position2di> offsets(text_size);
    std::vector<bool>              fallback(text_size);

    for (u32 i = 0; i<text_size; i++)
    {
        wchar_t c = text[i];

        if (c == L'\r' ||          // Windows breaks
            c == L'\n'    )        // Unix breaks
        {
            if(c==L'\r' && text[i+1]==L'\n') c = text[++i];
            offset.Y += (int)(MaxHeight*m_scale);
            offset.X  = position.UpperLeftCorner.X;
            if (hcenter)
                offset.X += (position.getWidth() - text_dimension.Width) >> 1;
            continue;
        }   // if lineBreak

        bool use_fallback_font = false;
        const SFontArea &area  = getAreaFromCharacter(c, &use_fallback_font);
        fallback[i]            = use_fallback_font;
        offset.X              += area.underhang;
        offsets.push_back(offset);
        // Invisible character. add something to the array anyway so that
        // indices from the various arrays remain in sync
        indices.push_back( Invisible.findFirst(c) < 0  ? area.spriteno
                                                       : -1            );
        offset.X += getCharWidth(area, fallback[i]);
    }   // for i<text_size

    // ---- do the actual rendering
    const int indiceAmount                    = indices.size();
    core::array< SGUISprite >& sprites        = SpriteBank->getSprites();
    core::array< core::rect<s32> >& positions = SpriteBank->getPositions();
    core::array< SGUISprite >* fallback_sprites;
    core::array< core::rect<s32> >* fallback_positions;
    if(m_fallback_font!=NULL)
    {
        fallback_sprites   = &m_fallback_font->SpriteBank->getSprites();
        fallback_positions = &m_fallback_font->SpriteBank->getPositions();
    }
    else
    {
        fallback_sprites   = NULL;
        fallback_positions = NULL;
    }

    const int spriteAmount      = sprites.size();
    for (int n=0; n<indiceAmount; n++)
    {
        const int spriteID = indices[n];
        if (!fallback[n] && (spriteID < 0 || spriteID >= spriteAmount)) continue;
        if (indices[n] == -1) continue;

        //assert(sprites[spriteID].Frames.size() > 0);

        const int texID = (fallback[n] ?
                           (*fallback_sprites)[spriteID].Frames[0].textureNumber :
                           sprites[spriteID].Frames[0].textureNumber);

        core::rect<s32> source = (fallback[n] ?
                                  (*fallback_positions)[(*fallback_sprites)[spriteID].Frames[0].rectNumber] :
                                  positions[sprites[spriteID].Frames[0].rectNumber]);

        const TextureInfo& info = (fallback[n] ?
                                   (*(m_fallback_font->m_texture_files.find(texID))).second :
                                   (*(m_texture_files.find(texID))).second
                                   );
        float char_scale = info.m_scale;

        core::dimension2d<s32> size = source.getSize();

        float scale = (fallback[n] ? m_scale*m_fallback_font_scale : m_scale);
        size.Width  = (int)(size.Width  * scale * char_scale);
        size.Height = (int)(size.Height * scale * char_scale);

        // align vertically if character is smaller
        int y_shift = (size.Height < MaxHeight*m_scale ? (int)((MaxHeight*m_scale - size.Height)/2.0f) : 0);

        core::rect<s32> dest(offsets[n] + core::position2di(0, y_shift), size);

        video::ITexture* texture = (fallback[n] ?
                                    m_fallback_font->SpriteBank->getTexture(texID) :
                                    SpriteBank->getTexture(texID) );

        /*
        if (fallback[n])
        {
            Log::info("ScalableFont", "Using fallback font %s; source area is %d, %d; size %d, %d; dest = %d, %d",
                core::stringc(texture->getName()).c_str(), source.UpperLeftCorner.X, source.UpperLeftCorner.Y,
                source.getWidth(), source.getHeight(), offsets[n].X, offsets[n].Y);
        }
        */

        if (texture == NULL)
        {
            // perform lazy loading

            if (fallback[n])
            {
                m_fallback_font->lazyLoadTexture(texID);
                texture = m_fallback_font->SpriteBank->getTexture(texID);
            }
            else
            {
                lazyLoadTexture(texID);
                texture = SpriteBank->getTexture(texID);
            }

            if (texture == NULL)
            {
                Log::warn("ScalableFont", "Character not found in current font");
                continue; // no such character
            }
        }

        if (m_black_border && charCollector == NULL)
        {
            // draw black border
            video::SColor black(color.getAlpha(),0,0,0);

            for (int x_delta=-2; x_delta<=2; x_delta++)
            {
                for (int y_delta=-2; y_delta<=2; y_delta++)
                {
                    if (x_delta == 0 || y_delta == 0) continue;
                    draw2DImage(texture,
                                dest + core::position2d<s32>(x_delta, y_delta),
                                source,
                                clip,
                                black, true);
                }
            }
        }

        if (fallback[n])
        {
            // TODO: don't hardcode colors?
            video::SColor orange(color.getAlpha(), 255, 100, 0);
            video::SColor yellow(color.getAlpha(), 255, 220, 15);
            video::SColor title_colors[] = {orange, yellow, orange, yellow};

            if (charCollector != NULL)
            {
                charCollector->collectChar(texture,
                    dest,
                    source,
                    title_colors);
            }
            else
            {
                draw2DImage(texture,
                    dest,
                    source,
                    clip,
                    title_colors, true);
            }
        }
        else
        {
            if (charCollector != NULL)
            {
                video::SColor colors[] = { color, color, color, color };
                charCollector->collectChar(texture,
                    dest,
                    source,
                    colors);
            }
            else
            {
                draw2DImage(texture,
                    dest,
                    source,
                    clip,
                    color, true);
            }
#ifdef FONT_DEBUG
            video::IVideoDriver* driver = GUIEngine::getDriver();
            driver->draw2DLine(core::position2d<s32>(dest.UpperLeftCorner.X,  dest.UpperLeftCorner.Y),
                               core::position2d<s32>(dest.UpperLeftCorner.X,  dest.LowerRightCorner.Y),
                               video::SColor(255, 255,0,0));
            driver->draw2DLine(core::position2d<s32>(dest.LowerRightCorner.X, dest.LowerRightCorner.Y),
                               core::position2d<s32>(dest.LowerRightCorner.X, dest.UpperLeftCorner.Y),
                               video::SColor(255, 255,0,0));
            driver->draw2DLine(core::position2d<s32>(dest.LowerRightCorner.X, dest.LowerRightCorner.Y),
                               core::position2d<s32>(dest.UpperLeftCorner.X,  dest.LowerRightCorner.Y),
                               video::SColor(255, 255,0,0));
            driver->draw2DLine(core::position2d<s32>(dest.UpperLeftCorner.X,  dest.UpperLeftCorner.Y),
                               core::position2d<s32>(dest.LowerRightCorner.X, dest.UpperLeftCorner.Y),
                               video::SColor(255, 255,0,0));
#endif
        }
    }
}
Пример #11
0
// ----------------------------------------------------------------------------
void FontWithFace::render(const core::stringw& text,
                          const core::rect<s32>& position,
                          const video::SColor& color, bool hcenter,
                          bool vcenter, const core::rect<s32>* clip,
                          FontSettings* font_settings,
                          FontCharCollector* char_collector)
{
    const bool is_bold_face = dynamic_cast<BoldFace*>(this);
    const bool black_border = font_settings ?
        font_settings->useBlackBorder() : false;
    const bool rtl = font_settings ? font_settings->isRTL() : false;
    const float scale = font_settings ? font_settings->getScale() : 1.0f;
    const float shadow = font_settings ? font_settings->useShadow() : false;

    if (shadow)
    {
        assert(font_settings);
        // Avoid infinite recursion
        font_settings->setShadow(false);

        core::rect<s32> shadowpos = position;
        shadowpos.LowerRightCorner.X += 2;
        shadowpos.LowerRightCorner.Y += 2;
        render(text, shadowpos, font_settings->getShadowColor(), hcenter,
            vcenter, clip, font_settings);

        // Set back
        font_settings->setShadow(true);
    }

    core::position2d<float> offset(float(position.UpperLeftCorner.X),
        float(position.UpperLeftCorner.Y));
    core::dimension2d<s32> text_dimension;

    if (rtl || hcenter || vcenter || clip)
    {
        text_dimension = getDimension(text.c_str(), font_settings);

        if (hcenter)
            offset.X += (position.getWidth() - text_dimension.Width) / 2;
        else if (rtl)
            offset.X += (position.getWidth() - text_dimension.Width);

        if (vcenter)
            offset.Y += (position.getHeight() - text_dimension.Height) / 2;
        if (clip)
        {
            core::rect<s32> clippedRect(core::position2d<s32>
                (s32(offset.X), s32(offset.Y)), text_dimension);
            clippedRect.clipAgainst(*clip);
            if (!clippedRect.isValid()) return;
        }
    }

    // Collect character locations
    const unsigned int text_size = text.size();
    core::array<s32> indices(text_size);
    core::array<core::position2d<float>> offsets(text_size);
    std::vector<bool> fallback(text_size);

    // Test again if lazy load char is needed,
    // as some text isn't drawn with getDimension
    insertCharacters(text.c_str());
    updateCharactersList();

    for (u32 i = 0; i < text_size; i++)
    {
        wchar_t c = text[i];

        if (c == L'\r' ||          // Windows breaks
            c == L'\n'    )        // Unix breaks
        {
            if (c==L'\r' && text[i+1]==L'\n')
                c = text[++i];
            offset.Y += m_font_max_height * scale;
            offset.X  = position.UpperLeftCorner.X;
            if (hcenter)
                offset.X += (position.getWidth() - text_dimension.Width) >> 1;
            continue;
        }   // if lineBreak

        bool use_fallback_font = false;
        const FontArea &area   = getAreaFromCharacter(c, &use_fallback_font);
        fallback[i]            = use_fallback_font;
        if (char_collector == NULL)
        {
            float glyph_offset_x = area.bearing_x *
                (fallback[i] ? m_fallback_font_scale : scale);
            float glyph_offset_y = area.offset_y *
                (fallback[i] ? m_fallback_font_scale : scale);
            offset.X += glyph_offset_x;
            offset.Y += glyph_offset_y;
            offsets.push_back(offset);
            offset.X -= glyph_offset_x;
            offset.Y -= glyph_offset_y;
        }
        else
        {
            // Prevent overwriting texture used by billboard text when
            // using lazy loading characters
            if (supportLazyLoadChar() && fallback[i])
            {
                const int cur_texno = m_fallback_font->getSpriteBank()
                    ->getSprites()[area.spriteno].Frames[0].textureNumber;
                if (cur_texno == int(m_fallback_font->getSpriteBank()
                    ->getTextureCount() - 1))
                {
                    m_fallback_font->createNewGlyphPage();
                }
            }
            else if (supportLazyLoadChar())
            {
                const int cur_texno = m_spritebank
                    ->getSprites()[area.spriteno].Frames[0].textureNumber;
                if (cur_texno == int(m_spritebank->getTextureCount() - 1))
                {
                    createNewGlyphPage();
                }
            }

            // Billboard text specific, use offset_y_bt instead
            float glyph_offset_x = area.bearing_x *
                (fallback[i] ? m_fallback_font_scale : scale);
            float glyph_offset_y = area.offset_y_bt *
                (fallback[i] ? m_fallback_font_scale : scale);
            offset.X += glyph_offset_x;
            offset.Y += glyph_offset_y;
            offsets.push_back(offset);
            offset.X -= glyph_offset_x;
            offset.Y -= glyph_offset_y;
        }

        indices.push_back(area.spriteno);
        offset.X += getCharWidth(area, fallback[i], scale);
    }   // for i < text_size

    // Do the actual rendering
    const int indice_amount                 = indices.size();
    core::array<gui::SGUISprite>& sprites   = m_spritebank->getSprites();
    core::array<core::rect<s32>>& positions = m_spritebank->getPositions();
    core::array<gui::SGUISprite>* fallback_sprites;
    core::array<core::rect<s32>>* fallback_positions;
    if (m_fallback_font != NULL)
    {
        fallback_sprites   = &m_fallback_font->m_spritebank->getSprites();
        fallback_positions = &m_fallback_font->m_spritebank->getPositions();
    }
    else
    {
        fallback_sprites   = NULL;
        fallback_positions = NULL;
    }

    const int sprite_amount = sprites.size();

    if ((black_border || is_bold_face) && char_collector == NULL)
    {
        // Draw black border first, to make it behind the real character
        // which make script language display better
        video::SColor black(color.getAlpha(),0,0,0);
        for (int n = 0; n < indice_amount; n++)
        {
            const int sprite_id = indices[n];
            if (!fallback[n] && (sprite_id < 0 || sprite_id >= sprite_amount))
                continue;
            if (indices[n] == -1) continue;

            const int tex_id = (fallback[n] ?
                (*fallback_sprites)[sprite_id].Frames[0].textureNumber :
                sprites[sprite_id].Frames[0].textureNumber);

            core::rect<s32> source = (fallback[n] ? (*fallback_positions)
                [(*fallback_sprites)[sprite_id].Frames[0].rectNumber] :
                positions[sprites[sprite_id].Frames[0].rectNumber]);

            core::dimension2d<float> size(0.0f, 0.0f);

            float cur_scale = (fallback[n] ? m_fallback_font_scale : scale);
            size.Width  = source.getSize().Width  * cur_scale;
            size.Height = source.getSize().Height * cur_scale;

            core::rect<float> dest(offsets[n], size);

            video::ITexture* texture = (fallback[n] ?
                m_fallback_font->m_spritebank->getTexture(tex_id) :
                m_spritebank->getTexture(tex_id));

            for (int x_delta = -2; x_delta <= 2; x_delta++)
            {
                for (int y_delta = -2; y_delta <= 2; y_delta++)
                {
                    if (x_delta == 0 || y_delta == 0) continue;
                    draw2DImage(texture, dest + core::position2d<float>
                        (float(x_delta), float(y_delta)), source, clip,
                        black, true);
                }
            }
        }
    }

    for (int n = 0; n < indice_amount; n++)
    {
        const int sprite_id = indices[n];
        if (!fallback[n] && (sprite_id < 0 || sprite_id >= sprite_amount))
            continue;
        if (indices[n] == -1) continue;

        const int tex_id = (fallback[n] ?
            (*fallback_sprites)[sprite_id].Frames[0].textureNumber :
            sprites[sprite_id].Frames[0].textureNumber);

        core::rect<s32> source = (fallback[n] ?
            (*fallback_positions)[(*fallback_sprites)[sprite_id].Frames[0]
            .rectNumber] : positions[sprites[sprite_id].Frames[0].rectNumber]);

        core::dimension2d<float> size(0.0f, 0.0f);

        float cur_scale = (fallback[n] ? m_fallback_font_scale : scale);
        size.Width  = source.getSize().Width  * cur_scale;
        size.Height = source.getSize().Height * cur_scale;

        core::rect<float> dest(offsets[n], size);

        video::ITexture* texture = (fallback[n] ?
            m_fallback_font->m_spritebank->getTexture(tex_id) :
            m_spritebank->getTexture(tex_id));

        if (fallback[n] || is_bold_face)
        {
            video::SColor top = GUIEngine::getSkin()->getColor("font::top");
            video::SColor bottom = GUIEngine::getSkin()
                ->getColor("font::bottom");
            top.setAlpha(color.getAlpha());
            bottom.setAlpha(color.getAlpha());

            video::SColor title_colors[] = {top, bottom, top, bottom};
            if (char_collector != NULL)
            {
                char_collector->collectChar(texture, dest, source,
                    title_colors);
            }
            else
            {
                draw2DImage(texture, dest, source, clip, title_colors, true);
            }
        }
        else
        {
            if (char_collector != NULL)
            {
                video::SColor colors[] = {color, color, color, color};
                char_collector->collectChar(texture, dest, source, colors);
            }
            else
            {
                draw2DImage(texture, dest, source, clip, color, true);
            }
        }
    }
}   // render
void MultiColumnFragmentainerGroup::collectLayerFragments(PaintLayerFragments& fragments, const LayoutRect& layerBoundingBox, const LayoutRect& dirtyRect) const
{
    // |layerBoundingBox| is in the flow thread coordinate space, relative to the top/left edge of
    // the flow thread, but note that it has been converted with respect to writing mode (so that
    // it's visual/physical in that sense).
    //
    // |dirtyRect| is visual, relative to the multicol container.
    //
    // Then there's the output from this method - the stuff we put into the list of fragments. The
    // fragment.paginationOffset point is the actual visual translation required to get from a
    // location in the flow thread to a location in a given column. The fragment.paginationClip
    // rectangle, on the other hand, is in flow thread coordinates, but otherwise completely
    // physical in terms of writing mode.

    LayoutMultiColumnFlowThread* flowThread = m_columnSet.multiColumnFlowThread();
    bool isHorizontalWritingMode = m_columnSet.isHorizontalWritingMode();

    // Put the layer bounds into flow thread-local coordinates by flipping it first. Since we're in
    // a layoutObject, most rectangles are represented this way.
    LayoutRect layerBoundsInFlowThread(layerBoundingBox);
    flowThread->flipForWritingMode(layerBoundsInFlowThread);

    // Now we can compare with the flow thread portions owned by each column. First let's
    // see if the rect intersects our flow thread portion at all.
    LayoutRect clippedRect(layerBoundsInFlowThread);
    clippedRect.intersect(m_columnSet.flowThreadPortionOverflowRect());
    if (clippedRect.isEmpty())
        return;

    // Now we know we intersect at least one column. Let's figure out the logical top and logical
    // bottom of the area we're checking.
    LayoutUnit layerLogicalTop = isHorizontalWritingMode ? layerBoundsInFlowThread.y() : layerBoundsInFlowThread.x();
    LayoutUnit layerLogicalBottom = (isHorizontalWritingMode ? layerBoundsInFlowThread.maxY() : layerBoundsInFlowThread.maxX());

    // Figure out the start and end columns for the layer and only check within that range so that
    // we don't walk the entire column row.
    unsigned startColumn;
    unsigned endColumn;
    columnIntervalForBlockRangeInFlowThread(layerLogicalTop, layerLogicalBottom, startColumn, endColumn);

    // Now intersect with the columns actually occupied by the dirty rect, to narrow it down even further.
    unsigned firstColumnInDirtyRect, lastColumnInDirtyRect;
    columnIntervalForVisualRect(dirtyRect, firstColumnInDirtyRect, lastColumnInDirtyRect);
    if (firstColumnInDirtyRect > endColumn || lastColumnInDirtyRect < startColumn)
        return; // The two column intervals are disjoint. There's nothing to collect.
    if (startColumn < firstColumnInDirtyRect)
        startColumn = firstColumnInDirtyRect;
    if (endColumn > lastColumnInDirtyRect)
        endColumn = lastColumnInDirtyRect;
    ASSERT(endColumn >= startColumn);

    for (unsigned i = startColumn; i <= endColumn; i++) {
        PaintLayerFragment fragment;

        // Set the physical translation offset.
        fragment.paginationOffset = toLayoutPoint(flowThreadTranslationAtOffset(logicalTopInFlowThreadAt(i)));

        // Set the overflow clip rect that corresponds to the column.
        fragment.paginationClip = flowThreadPortionOverflowRectAt(i);
        // Flip it into more a physical (PaintLayer-style) rectangle.
        flowThread->flipForWritingMode(fragment.paginationClip);

        fragments.append(fragment);
    }
}
Пример #13
0
	void GroupEditor::drawContents(Renderer2D &out) const {
		int2 offset = innerOffset();

		for(int n = 0; n < m_tile_group->entryCount(); n++)
		   m_tile_group->entryTile(n)->m_temp = n;

		IRect clip_rect(int2(0, 0), clippedRect().size());

		for(int n = 0; n < (int)m_tile_list.size(); n++) {
			const ui::TileList::Entry &entry = m_tile_list[n];
			entry.is_selected = m_mode == mAddRemove?
				m_tile_group->isValidEntryId(entry.tile->m_temp, entry.tile) :
				entry.group_id == m_selected_group_id;

			IRect tile_rect = entry.tile->rect();
			int2 pos = entry.pos - tile_rect.min - offset;

			if(areOverlapping(clip_rect, tile_rect + pos))
				entry.tile->draw(out, pos);
		}
		
		DTexture::unbind();
		for(int n = 0; n < (int)m_tile_list.size(); n++) {
			const ui::TileList::Entry &entry = m_tile_list[n];
			if(!entry.is_selected)
				continue;
		
			Color col = m_tile_group->isEntryDirty(entry.tile->m_temp)? ColorId::red : ColorId::white;	
			int2 pos = entry.pos - offset;
			out.addRect(IRect(pos, pos + entry.size), col);
		}

		if(m_mode == mModify && m_selected_group_id != -1) {	
			IRect edit_rect(clippedRect().max - int2(280, 250), clippedRect().max - int2(5, 0));
			int2 center = edit_rect.center();

			out.setViewPos(-center);
			int2 half_size = edit_rect.size() / 2;
			out.addFilledRect(IRect(-half_size, half_size), FColor(0.3f, 0.3f, 0.3f));
			drawBBox(out, IBox({-9, 0, -9}, {9, 1, 9}), ColorId::white);

			auto font = res::getFont(WindowStyle::fonts[0]);

			for(int n = 0; n < TileGroup::Group::side_count; n++) {
				out.setViewPos(-center - worldToScreen(TileGroup::Group::s_side_offsets[n] * 9));
				font->draw(out, float2(0, 0), {ColorId::white}, format("%d", m_tile_group->groupSurface(m_selected_group_id, n)));
			}
				
			out.setViewPos(-center +edit_rect.size() / 2);
			font->draw(out, float2(0, 0), {ColorId::white}, format("setting surface: %d", m_selected_surface_id));

			/*
			const char *names[] = {
				"",
				"snow",
				"gravel",
				"dirt",
				"grass",
				"mud",
				"mud_cracked",
				"sand",
				"green goo",
			};

			out.setViewPos(-int2(bottom_rect.max.x - 200, bottom_rect.min.y));
			for(int n = 0; n < arraySize(names); n++)
				font->draw(int2(0, 10), ColorId::white,
						m_selected_surface_id == n? "%d: [%s]\n" : "%d: %s\n", n, names[n]); */
			out.setViewPos(-clippedRect().min);
		}

		if(m_current_entry)
			m_font->draw(out, float2(5, height() - 20), {ColorId::white, ColorId::black},
					format("%s", m_current_entry->tile->resourceName().c_str()));
	}
Пример #14
0
void RenderMultiColumnSet::collectLayerFragments(LayerFragments& fragments, const LayoutRect& layerBoundingBox, const LayoutRect& dirtyRect)
{
    // The two rectangles passed to this method are physical, except that we pretend that there's
    // only one long column (that's how a flow thread works).
    //
    // Then there's the output from this method - the stuff we put into the list of fragments. The
    // fragment.paginationOffset point is the actual physical translation required to get from a
    // location in the flow thread to a location in a given column. The fragment.paginationClip
    // rectangle, on the other hand, is in the same coordinate system as the two rectangles passed
    // to this method (flow thread coordinates).
    //
    // All other rectangles in this method are sized physically, and the inline direction coordinate
    // is physical too, but the block direction coordinate is "logical top". This is the same as
    // e.g. RenderBox::frameRect(). These rectangles also pretend that there's only one long column,
    // i.e. they are for the flow thread.

    // Put the layer bounds into flow thread-local coordinates by flipping it first. Since we're in
    // a renderer, most rectangles are represented this way.
    LayoutRect layerBoundsInFlowThread(layerBoundingBox);
    flowThread()->flipForWritingMode(layerBoundsInFlowThread);

    // Now we can compare with the flow thread portions owned by each column. First let's
    // see if the rect intersects our flow thread portion at all.
    LayoutRect clippedRect(layerBoundsInFlowThread);
    clippedRect.intersect(RenderRegion::flowThreadPortionOverflowRect());
    if (clippedRect.isEmpty())
        return;

    // Now we know we intersect at least one column. Let's figure out the logical top and logical
    // bottom of the area we're checking.
    LayoutUnit layerLogicalTop = isHorizontalWritingMode() ? layerBoundsInFlowThread.y() : layerBoundsInFlowThread.x();
    LayoutUnit layerLogicalBottom = (isHorizontalWritingMode() ? layerBoundsInFlowThread.maxY() : layerBoundsInFlowThread.maxX()) - 1;

    // Figure out the start and end columns and only check within that range so that we don't walk the
    // entire column set.
    unsigned startColumn = columnIndexAtOffset(layerLogicalTop);
    unsigned endColumn = columnIndexAtOffset(layerLogicalBottom);

    LayoutUnit colLogicalWidth = computedColumnWidth();
    LayoutUnit colGap = columnGap();
    unsigned colCount = columnCount();

    for (unsigned i = startColumn; i <= endColumn; i++) {
        // Get the portion of the flow thread that corresponds to this column.
        LayoutRect flowThreadPortion = flowThreadPortionRectAt(i);

        // Now get the overflow rect that corresponds to the column.
        LayoutRect flowThreadOverflowPortion = flowThreadPortionOverflowRect(flowThreadPortion, i, colCount, colGap);

        // In order to create a fragment we must intersect the portion painted by this column.
        LayoutRect clippedRect(layerBoundsInFlowThread);
        clippedRect.intersect(flowThreadOverflowPortion);
        if (clippedRect.isEmpty())
            continue;

        // We also need to intersect the dirty rect. We have to apply a translation and shift based off
        // our column index.
        LayoutPoint translationOffset;
        LayoutUnit inlineOffset = i * (colLogicalWidth + colGap);
        if (!style()->isLeftToRightDirection())
            inlineOffset = -inlineOffset;
        translationOffset.setX(inlineOffset);
        LayoutUnit blockOffset = isHorizontalWritingMode() ? -flowThreadPortion.y() : -flowThreadPortion.x();
        if (isFlippedBlocksWritingMode(style()->writingMode()))
            blockOffset = -blockOffset;
        translationOffset.setY(blockOffset);
        if (!isHorizontalWritingMode())
            translationOffset = translationOffset.transposedPoint();
        // FIXME: The translation needs to include the multicolumn set's content offset within the
        // multicolumn block as well. This won't be an issue until we start creating multiple multicolumn sets.

        // Shift the dirty rect to be in flow thread coordinates with this translation applied.
        LayoutRect translatedDirtyRect(dirtyRect);
        translatedDirtyRect.moveBy(-translationOffset);

        // See if we intersect the dirty rect.
        clippedRect = layerBoundingBox;
        clippedRect.intersect(translatedDirtyRect);
        if (clippedRect.isEmpty())
            continue;

        // Something does need to paint in this column. Make a fragment now and supply the physical translation
        // offset and the clip rect for the column with that offset applied.
        LayerFragment fragment;
        fragment.paginationOffset = translationOffset;

        LayoutRect flippedFlowThreadOverflowPortion(flowThreadOverflowPortion);
        // Flip it into more a physical (RenderLayer-style) rectangle.
        flowThread()->flipForWritingMode(flippedFlowThreadOverflowPortion);
        fragment.paginationClip = flippedFlowThreadOverflowPortion;
        fragments.append(fragment);
    }
}
void MultiColumnFragmentainerGroup::collectLayerFragments(DeprecatedPaintLayerFragments& fragments, const LayoutRect& layerBoundingBox, const LayoutRect& dirtyRect) const
{
    // |layerBoundingBox| is in the flow thread coordinate space, relative to the top/left edge of
    // the flow thread, but note that it has been converted with respect to writing mode (so that
    // it's visual/physical in that sense).
    //
    // |dirtyRect| is visual, relative to the multicol container.
    //
    // Then there's the output from this method - the stuff we put into the list of fragments. The
    // fragment.paginationOffset point is the actual visual translation required to get from a
    // location in the flow thread to a location in a given column. The fragment.paginationClip
    // rectangle, on the other hand, is in flow thread coordinates, but otherwise completely
    // physical in terms of writing mode.
    //
    // All other rectangles in this method are sized physically, and the inline direction coordinate
    // is physical too, but the block direction coordinate is "logical top". This is the same as
    // e.g. LayoutBox::frameRect(). These rectangles also pretend that there's only one long column,
    // i.e. they are for the flow thread.

    LayoutMultiColumnFlowThread* flowThread = m_columnSet.multiColumnFlowThread();
    bool isHorizontalWritingMode = m_columnSet.isHorizontalWritingMode();

    // Put the layer bounds into flow thread-local coordinates by flipping it first. Since we're in
    // a layoutObject, most rectangles are represented this way.
    LayoutRect layerBoundsInFlowThread(layerBoundingBox);
    flowThread->flipForWritingMode(layerBoundsInFlowThread);

    // Now we can compare with the flow thread portions owned by each column. First let's
    // see if the rect intersects our flow thread portion at all.
    LayoutRect clippedRect(layerBoundsInFlowThread);
    clippedRect.intersect(m_columnSet.flowThreadPortionOverflowRect());
    if (clippedRect.isEmpty())
        return;

    // Now we know we intersect at least one column. Let's figure out the logical top and logical
    // bottom of the area we're checking.
    LayoutUnit layerLogicalTop = isHorizontalWritingMode ? layerBoundsInFlowThread.y() : layerBoundsInFlowThread.x();
    LayoutUnit layerLogicalBottom = (isHorizontalWritingMode ? layerBoundsInFlowThread.maxY() : layerBoundsInFlowThread.maxX()) - 1;

    // Figure out the start and end columns and only check within that range so that we don't walk the
    // entire column row.
    unsigned startColumn = columnIndexAtOffset(layerLogicalTop);
    unsigned endColumn = columnIndexAtOffset(layerLogicalBottom);

    LayoutUnit colLogicalWidth = m_columnSet.pageLogicalWidth();
    LayoutUnit colGap = m_columnSet.columnGap();
    unsigned colCount = actualColumnCount();

    bool progressionIsInline = flowThread->progressionIsInline();
    bool leftToRight = m_columnSet.style()->isLeftToRightDirection();

    LayoutUnit initialBlockOffset = m_columnSet.logicalTop() + logicalTop() - flowThread->logicalTop();

    for (unsigned i = startColumn; i <= endColumn; i++) {
        // Get the portion of the flow thread that corresponds to this column.
        LayoutRect flowThreadPortion = flowThreadPortionRectAt(i);

        // Now get the overflow rect that corresponds to the column.
        LayoutRect flowThreadOverflowPortion = flowThreadPortionOverflowRect(flowThreadPortion, i, colCount, colGap);

        // In order to create a fragment we must intersect the portion painted by this column.
        LayoutRect clippedRect(layerBoundsInFlowThread);
        clippedRect.intersect(flowThreadOverflowPortion);
        if (clippedRect.isEmpty())
            continue;

        // We also need to intersect the dirty rect. We have to apply a translation and shift based off
        // our column index.
        LayoutPoint translationOffset;
        LayoutUnit inlineOffset = progressionIsInline ? i * (colLogicalWidth + colGap) : LayoutUnit();
        if (!leftToRight)
            inlineOffset = -inlineOffset;
        translationOffset.setX(inlineOffset);
        LayoutUnit blockOffset;
        if (progressionIsInline) {
            blockOffset = initialBlockOffset + (isHorizontalWritingMode ? -flowThreadPortion.y() : -flowThreadPortion.x());
        } else {
            // Column gap can apply in the block direction for page fragmentainers.
            // There is currently no spec which calls for column-gap to apply
            // for page fragmentainers at all, but it's applied here for compatibility
            // with the old multicolumn implementation.
            blockOffset = i * colGap;
        }
        if (isFlippedBlocksWritingMode(m_columnSet.style()->writingMode()))
            blockOffset = -blockOffset;
        translationOffset.setY(blockOffset);
        if (!isHorizontalWritingMode)
            translationOffset = translationOffset.transposedPoint();

        // Shift the dirty rect to be in flow thread coordinates with this translation applied.
        LayoutRect translatedDirtyRect(dirtyRect);
        translatedDirtyRect.moveBy(-translationOffset);

        // See if we intersect the dirty rect.
        clippedRect = layerBoundingBox;
        clippedRect.intersect(translatedDirtyRect);
        if (clippedRect.isEmpty())
            continue;

        // Something does need to paint in this column. Make a fragment now and supply the physical translation
        // offset and the clip rect for the column with that offset applied.
        DeprecatedPaintLayerFragment fragment;
        fragment.paginationOffset = translationOffset;

        LayoutRect flippedFlowThreadOverflowPortion(flowThreadOverflowPortion);
        // Flip it into more a physical (DeprecatedPaintLayer-style) rectangle.
        flowThread->flipForWritingMode(flippedFlowThreadOverflowPortion);
        fragment.paginationClip = flippedFlowThreadOverflowPortion;
        fragments.append(fragment);
    }
}
Пример #16
0
void RenderMultiColumnSet::collectLayerFragments(LayerFragments& fragments, const LayoutRect& layerBoundingBox, const LayoutRect& dirtyRect)
{
    // Let's start by introducing the different coordinate systems involved here. They are different
    // in how they deal with writing modes and columns. RenderLayer rectangles tend to be more
    // physical than the rectangles used in RenderObject & co.
    //
    // The two rectangles passed to this method are physical, except that we pretend that there's
    // only one long column (that's the flow thread). They are relative to the top left corner of
    // the flow thread. All rectangles being compared to the dirty rect also need to be in this
    // coordinate system.
    //
    // Then there's the output from this method - the stuff we put into the list of fragments. The
    // translationOffset point is the actual physical translation required to get from a location in
    // the flow thread to a location in some column. The paginationClip rectangle is in the same
    // coordinate system as the two rectangles passed to this method (i.e. physical, in flow thread
    // coordinates, pretending that there's only one long column).
    //
    // All other rectangles in this method are slightly less physical, when it comes to how they are
    // used with different writing modes, but they aren't really logical either. They are just like
    // RenderBox::frameRect(). More precisely, the sizes are physical, and the inline direction
    // coordinate is too, but the block direction coordinate is always "logical top". These
    // rectangles also pretend that there's only one long column, i.e. they are for the flow thread.
    //
    // To sum up: input and output from this method are "physical" RenderLayer-style rectangles and
    // points, while inside this method we mostly use the RenderObject-style rectangles (with the
    // block direction coordinate always being logical top).

    // Put the layer bounds into flow thread-local coordinates by flipping it first. Since we're in
    // a renderer, most rectangles are represented this way.
    LayoutRect layerBoundsInFlowThread(layerBoundingBox);
    flowThread()->flipForWritingMode(layerBoundsInFlowThread);

    // Now we can compare with the flow thread portions owned by each column. First let's
    // see if the rect intersects our flow thread portion at all.
    LayoutRect clippedRect(layerBoundsInFlowThread);
    clippedRect.intersect(RenderRegion::flowThreadPortionOverflowRect());
    if (clippedRect.isEmpty())
        return;
    
    // Now we know we intersect at least one column. Let's figure out the logical top and logical
    // bottom of the area we're checking.
    LayoutUnit layerLogicalTop = isHorizontalWritingMode() ? layerBoundsInFlowThread.y() : layerBoundsInFlowThread.x();
    LayoutUnit layerLogicalBottom = (isHorizontalWritingMode() ? layerBoundsInFlowThread.maxY() : layerBoundsInFlowThread.maxX()) - 1;
    
    // Figure out the start and end columns and only check within that range so that we don't walk the
    // entire column set.
    unsigned startColumn = columnIndexAtOffset(layerLogicalTop);
    unsigned endColumn = columnIndexAtOffset(layerLogicalBottom);
    
    LayoutUnit colLogicalWidth = computedColumnWidth();
    LayoutUnit colGap = columnGap();
    unsigned colCount = columnCount();
    
    RenderBlockFlow* parentFlow = toRenderBlockFlow(parent());
    bool progressionReversed = parentFlow->multiColumnFlowThread()->progressionIsReversed();
    bool progressionIsInline = parentFlow->multiColumnFlowThread()->progressionIsInline();
    
    LayoutUnit initialBlockOffset = initialBlockOffsetForPainting();
    
    for (unsigned i = startColumn; i <= endColumn; i++) {
        // Get the portion of the flow thread that corresponds to this column.
        LayoutRect flowThreadPortion = flowThreadPortionRectAt(i);
        
        // Now get the overflow rect that corresponds to the column.
        LayoutRect flowThreadOverflowPortion = flowThreadPortionOverflowRect(flowThreadPortion, i, colCount, colGap);

        // In order to create a fragment we must intersect the portion painted by this column.
        LayoutRect clippedRect(layerBoundsInFlowThread);
        clippedRect.intersect(flowThreadOverflowPortion);
        if (clippedRect.isEmpty())
            continue;
        
        // We also need to intersect the dirty rect. We have to apply a translation and shift based off
        // our column index.
        LayoutPoint translationOffset;
        LayoutUnit inlineOffset = progressionIsInline ? i * (colLogicalWidth + colGap) : LayoutUnit();
        
        bool leftToRight = style().isLeftToRightDirection() ^ progressionReversed;
        if (!leftToRight) {
            inlineOffset = -inlineOffset;
            if (progressionReversed)
                inlineOffset += contentLogicalWidth() - colLogicalWidth;
        }
        translationOffset.setX(inlineOffset);
        LayoutUnit blockOffset = initialBlockOffset + (isHorizontalWritingMode() ? -flowThreadPortion.y() : -flowThreadPortion.x());
        if (!progressionIsInline) {
            if (!progressionReversed)
                blockOffset = i * colGap;
            else
                blockOffset -= i * (computedColumnHeight() + colGap);
        }
        if (isFlippedBlocksWritingMode(style().writingMode()))
            blockOffset = -blockOffset;
        translationOffset.setY(blockOffset);
        if (!isHorizontalWritingMode())
            translationOffset = translationOffset.transposedPoint();
        // FIXME: The translation needs to include the multicolumn set's content offset within the
        // multicolumn block as well. This won't be an issue until we start creating multiple multicolumn sets.

        // Shift the dirty rect to be in flow thread coordinates with this translation applied.
        LayoutRect translatedDirtyRect(dirtyRect);
        translatedDirtyRect.moveBy(-translationOffset);
        
        // See if we intersect the dirty rect.
        clippedRect = layerBoundingBox;
        clippedRect.intersect(translatedDirtyRect);
        if (clippedRect.isEmpty())
            continue;
        
        // Something does need to paint in this column. Make a fragment now and supply the physical translation
        // offset and the clip rect for the column with that offset applied.
        LayerFragment fragment;
        fragment.paginationOffset = translationOffset;

        LayoutRect flippedFlowThreadOverflowPortion(flowThreadOverflowPortion);
        // Flip it into more a physical (RenderLayer-style) rectangle.
        flowThread()->flipForWritingMode(flippedFlowThreadOverflowPortion);
        fragment.paginationClip = flippedFlowThreadOverflowPortion;
        fragments.append(fragment);
    }
}
Пример #17
0
	void EntitiesEditor::drawContents(Renderer2D &out) const {
		m_view.updateVisibility();
		SceneRenderer renderer(clippedRect(), m_view.pos());
		
		{
			vector<int> visible_ids;
			visible_ids.reserve(1024);
			m_tile_map.findAll(visible_ids, renderer.targetRect(), Flags::all | Flags::visible);

			for(int i = 0; i < (int)visible_ids.size(); i++) {
				auto &object = m_tile_map[visible_ids[i]];
				int3 pos(object.bbox.min);
				object.ptr->addToRender(renderer, pos, Color::white);
			}

			visible_ids.clear();
			m_entity_map.findAll(visible_ids, renderer.targetRect(), Flags::all | Flags::visible);
			
			vector<char> selection_map(m_entity_map.size(), 0);
			vector<float3> old_positions(m_selected_ids.size());

			for(int n = 0; n < (int)m_selected_ids.size(); n++) {
				selection_map[m_selected_ids[n]] = 1;
				visible_ids.push_back(m_selected_ids[n]);

				if(m_is_moving) {
					auto &object = m_entity_map[m_selected_ids[n]];
					old_positions[n] = object.ptr->pos();
					object.ptr->setPos(old_positions[n] + float3(m_move_offset));
					m_entity_map.update(m_selected_ids[n]);
				}
			}

			sort(visible_ids.begin(), visible_ids.end());
			visible_ids.resize(std::unique(visible_ids.begin(), visible_ids.end()) - visible_ids.begin());
		
			for(int n = 0; n < (int)visible_ids.size(); n++) {
				auto &object = m_entity_map[visible_ids[n]];
				float3 old_pos = object.ptr->pos();
				bool is_selected = selection_map[visible_ids[n]];

				FBox bbox = object.ptr->boundingBox();

				if(object.ptr->typeId() == EntityId::trigger) {
					renderer.addBox(bbox, Color(Color::green, 64), true);
					renderer.addBox(FBox(bbox.min + float3(0.1, 0.1, 0.1), bbox.max - float3(0.1, 0.1, 0.1)), Color::green);
				}
				else {
					object.ptr->addToRender(renderer);
				}

				bool is_colliding = m_tile_map.findAny(bbox) != -1 || m_entity_map.findAny(bbox, visible_ids[n]) != -1;
				if(is_colliding)
					renderer.addBox(bbox, Color::red);
				if(is_selected) {
					if(!is_colliding)
						renderer.addBox(bbox, Color::white);
					FBox overground_box = computeOvergroundBox(bbox);
					if(!overground_box.isEmpty())
						renderer.addBox(overground_box, Color::yellow);
				}
			}

			if(m_is_moving) for(int n = 0; n < (int)m_selected_ids.size(); n++) {
				auto &object = m_entity_map[m_selected_ids[n]];
				object.ptr->setPos(old_positions[n]);
				m_entity_map.update(m_selected_ids[n]);
			}
		}

		if(m_proto && m_mode == Mode::placing) {
			m_proto->setPos(m_cursor_pos);
			m_proto->addToRender(renderer);
			FBox bbox = m_proto->boundingBox();

			bool is_colliding = m_tile_map.findAny(bbox) != -1 || m_entity_map.findAny(bbox) != -1;
			renderer.addBox(bbox, is_colliding? Color::red : Color::white);
			if(bbox.max.y == bbox.min.y)
				bbox.max.y += 1.0f;

			FBox overground_box = computeOvergroundBox(bbox);
			if(!overground_box.isEmpty())
				renderer.addBox(overground_box, Color::yellow);
		}

		renderer.render();
		if(m_mode == Mode::selecting && m_is_selecting)
			out.addRect(m_selection - m_view.pos(), Color::white);

		out.setScissorRect(clippedRect());
		out.setViewPos(-clippedRect().min + m_view.pos());
		m_view.drawGrid(out);

		out.setViewPos(-clippedRect().min);
		auto font = res::getFont(WindowStyle::fonts[1]);

		font->draw(out, int2(0, clippedRect().height() - 25), {Color::white, Color::black},
				format("Cursor: (%.0f, %.0f, %.0f)  Grid: %d Mode: %s\n",
				m_cursor_pos.x, m_cursor_pos.y, m_cursor_pos.z, m_view.gridHeight(), EntitiesEditorMode::toString(m_mode)));
	}
Пример #18
0
//! draws some text and clips it to the specified rectangle if wanted
void CGUIFont::draw(const core::stringw& text, const core::rect<s32>& position,
                    video::SColor color,
                    bool hcenter, bool vcenter, const core::rect<s32>* clip
                   )
{
    if (!Driver)
        return;

    core::dimension2d<s32> textDimension;	// NOTE: don't make this u32 or the >> later on can fail when the dimension width is < position width
    core::position2d<s32> offset = position.UpperLeftCorner;

    if (hcenter || vcenter || clip)
        textDimension = getDimension(text.c_str());

    if (hcenter)
        offset.X += (position.getWidth() - textDimension.Width) >> 1;

    if (vcenter)
        offset.Y += (position.getHeight() - textDimension.Height) >> 1;

    if (clip)
    {
        core::rect<s32> clippedRect(offset, textDimension);
        clippedRect.clipAgainst(*clip);
        if (!clippedRect.isValid())
            return;
    }

    core::array<u32> indices(text.size());
    core::array<core::position2di> offsets(text.size());

    for(u32 i = 0; i < text.size(); i++)
    {
        wchar_t c = text[i];

        bool lineBreak=false;
        if ( c == L'\r') // Mac or Windows breaks
        {
            lineBreak = true;
            if ( text[i + 1] == L'\n') // Windows breaks
                c = text[++i];
        }
        else if ( c == L'\n') // Unix breaks
        {
            lineBreak = true;
        }

        if (lineBreak)
        {
            offset.Y += MaxHeight;
            offset.X = position.UpperLeftCorner.X;

            if ( hcenter )
            {
                offset.X += (position.getWidth() - textDimension.Width) >> 1;
            }
            continue;
        }

        SFontArea& area = Areas[getAreaFromCharacter(c)];

        offset.X += area.underhang;
        if ( Invisible.findFirst ( c ) < 0 )
        {
            indices.push_back(area.spriteno);
            offsets.push_back(offset);
        }

        offset.X += area.width + area.overhang + GlobalKerningWidth;
    }

    SpriteBank->draw2DSpriteBatch(indices, offsets, clip, color);
}
Пример #19
0
void RenderMultiColumnSet::collectLayerFragments(Vector<LayerFragment>& fragments, const LayoutRect& layerBoundingBox, const LayoutRect& dirtyRect)
{
    // Put the layer bounds into flow thread-local coordinates by flipping it first.
    LayoutRect layerBoundsInFlowThread(layerBoundingBox);
    flowThread()->flipForWritingMode(layerBoundsInFlowThread);

    // Do the same for the dirty rect.
    LayoutRect dirtyRectInFlowThread(dirtyRect);
    flowThread()->flipForWritingMode(dirtyRectInFlowThread);

    // Now we can compare with the flow thread portions owned by each column. First let's
    // see if the rect intersects our flow thread portion at all.
    LayoutRect clippedRect(layerBoundsInFlowThread);
    clippedRect.intersect(RenderRegion::flowThreadPortionOverflowRect());
    if (clippedRect.isEmpty())
        return;
    
    // Now we know we intersect at least one column. Let's figure out the logical top and logical
    // bottom of the area we're checking.
    LayoutUnit layerLogicalTop = isHorizontalWritingMode() ? layerBoundsInFlowThread.y() : layerBoundsInFlowThread.x();
    LayoutUnit layerLogicalBottom = (isHorizontalWritingMode() ? layerBoundsInFlowThread.maxY() : layerBoundsInFlowThread.maxX()) - 1;
    
    // Figure out the start and end columns and only check within that range so that we don't walk the
    // entire column set.
    unsigned startColumn = columnIndexAtOffset(layerLogicalTop);
    unsigned endColumn = columnIndexAtOffset(layerLogicalBottom);
    
    LayoutUnit colLogicalWidth = computedColumnWidth();
    LayoutUnit colGap = columnGap();
    unsigned colCount = columnCount();
    
    for (unsigned i = startColumn; i <= endColumn; i++) {
        // Get the portion of the flow thread that corresponds to this column.
        LayoutRect flowThreadPortion = flowThreadPortionRectAt(i);
        
        // Now get the overflow rect that corresponds to the column.
        LayoutRect flowThreadOverflowPortion = flowThreadPortionOverflowRect(flowThreadPortion, i, colCount, colGap);

        // In order to create a fragment we must intersect the portion painted by this column.
        LayoutRect clippedRect(layerBoundsInFlowThread);
        clippedRect.intersect(flowThreadOverflowPortion);
        if (clippedRect.isEmpty())
            continue;
        
        // We also need to intersect the dirty rect. We have to apply a translation and shift based off
        // our column index.
        LayoutPoint translationOffset;
        LayoutUnit inlineOffset = i * (colLogicalWidth + colGap);
        if (!style()->isLeftToRightDirection())
            inlineOffset = -inlineOffset;
        translationOffset.setX(inlineOffset);
        LayoutUnit blockOffset = isHorizontalWritingMode() ? -flowThreadPortion.y() : -flowThreadPortion.x();
        if (isFlippedBlocksWritingMode(style()->writingMode()))
            blockOffset = -blockOffset;
        translationOffset.setY(blockOffset);
        if (!isHorizontalWritingMode())
            translationOffset = translationOffset.transposedPoint();
        // FIXME: The translation needs to include the multicolumn set's content offset within the
        // multicolumn block as well. This won't be an issue until we start creating multiple multicolumn sets.

        // Shift the dirty rect to be in flow thread coordinates with this translation applied.
        LayoutRect translatedDirtyRect(dirtyRectInFlowThread);
        translatedDirtyRect.moveBy(-translationOffset);
        
        // See if we intersect the dirty rect.
        clippedRect = layerBoundsInFlowThread;
        clippedRect.intersect(translatedDirtyRect);
        if (clippedRect.isEmpty())
            continue;
        
        // Something does need to paint in this column. Make a fragment now and supply the physical translation
        // offset and the clip rect for the column with that offset applied.
        LayerFragment fragment;
        fragment.paginationOffset = translationOffset;
        
        LayoutRect flippedFlowThreadOverflowPortion(flowThreadOverflowPortion);
        flipForWritingMode(flippedFlowThreadOverflowPortion);
        fragment.paginationClip = flippedFlowThreadOverflowPortion;
        fragments.append(fragment);
    }
}
Пример #20
0
void wxPlotDrawerMarker::Draw(wxDC *dc, const wxArrayPlotMarker& markers)
{
    wxCHECK_RET(dc && m_owner, wxT("dc or owner"));
    INITIALIZE_FAST_GRAPHICS

    wxRect dcRect(GetDCRect());
    wxRect2DDouble subViewRect = m_owner->GetPlotRectFromClientRect( dcRect );

    double x0 = 0, y0 = 0, x1 = 0, y1 = 0;
    int n, count = markers.GetCount();
    for (n = 0; n < count; n++)
    {
        const wxPlotMarker &marker = markers[n];
        wxCHECK_RET(marker.Ok(), wxT("Invalid marker"));
        wxRect2DDouble r = marker.GetPlotRect();
        x0 = r.m_x;
        y0 = r.m_y;
        x1 = r.GetRight();
        y1 = r.GetBottom();

        if (marker.GetPen().Ok())
            dc->SetPen(marker.GetPen().GetPen());
        if (marker.GetBrush().Ok())
            dc->SetBrush(marker.GetBrush().GetBrush());

        // determine what to draw
        int marker_type = marker.GetMarkerType();
        wxSize size     = marker.GetSize();

        if (marker_type == wxPLOTMARKER_BITMAP)
        {
            wxBitmap bmp(marker.GetBitmap());
            int w = bmp.GetWidth(), h = bmp.GetHeight();
            // FIXME - add scaling and shifting later - maybe
            int i0 = m_owner->GetClientCoordFromPlotX(x0);
            int j0 = m_owner->GetClientCoordFromPlotY(y0);
            dc->DrawBitmap(bmp, RINT(i0 - w/2.0), RINT(j0 - h/2.0), true);
        }
        else if (marker_type == wxPLOTMARKER_LINE)
        {
            if (ClipLineToRect(x0, y0, x1, y1, subViewRect) != ClippedOut)
            {
                int i0 = m_owner->GetClientCoordFromPlotX(x0);
                int j0 = m_owner->GetClientCoordFromPlotY(y0);
                int i1 = m_owner->GetClientCoordFromPlotX(x1);
                int j1 = m_owner->GetClientCoordFromPlotY(y1);
                wxPLOTCTRL_DRAW_LINE(dc, window, pen, i0, j0, i1, j1);
            }
        }
        else if (marker_type == wxPLOTMARKER_ELLIPSE)
        {
            // fixed pixel size
            if ((size.x > 0) && (size.y > 0))
            {
                if (ClipLineToRect(x0, y0, x1, y1, subViewRect) != ClippedOut)
                {
                    int i0 = m_owner->GetClientCoordFromPlotX(x0);
                    int j0 = m_owner->GetClientCoordFromPlotY(y0);
                    wxPLOTCTRL_DRAW_ELLIPSE(dc, window, pen, i0, j0, size.x, size.y);
                }
            }
/*
            else if (ClipLineToRect(x0, y0, x1, y1, subViewRect) != ClippedOut)
            {
                int i0 = m_owner->GetClientCoordFromPlotX(x0);
                int j0 = m_owner->GetClientCoordFromPlotY(y0);
                int i1 = m_owner->GetClientCoordFromPlotX(x1);
                int j1 = m_owner->GetClientCoordFromPlotY(y1);
                wxPLOTCTRL_DRAW_ELLIPSE(dc, window, pen, i0, j0, i1, j1);
            }
*/
        }
        else // figure out the rest
        {
            // we may ignore type if rect is in certain states

            bool is_horiz = r.m_width  < 0;
            bool is_vert  = r.m_height < 0;

            bool cross = is_horiz && is_vert;

            if (is_horiz)
            {
                x0 = subViewRect.m_x - subViewRect.m_width; // push outside win
                x1 = subViewRect.GetRight() + subViewRect.m_width;
            }
            if (is_vert)
            {
                y0 = subViewRect.m_y - subViewRect.m_height;
                y1 = subViewRect.GetBottom() + subViewRect.m_height;
            }

            if ((marker_type == wxPLOTMARKER_POINT) || ((x0 == x1) && (y0 == y1)))
            {
                if (ClipLineToRect(x0, y0, x1, y1, subViewRect) != ClippedOut)
                {
                    int i0 = m_owner->GetClientCoordFromPlotX(x0);
                    int j0 = m_owner->GetClientCoordFromPlotY(y0);
                    dc->DrawPoint(i0, j0);
                }
            }
            else if ((marker_type == wxPLOTMARKER_VERT_LINE) || ((x0 == x1) && (y0 != y1)))
            {
                if (ClipLineToRect(x0, y0, x1, y1, subViewRect) != ClippedOut)
                {
                    int i0 = m_owner->GetClientCoordFromPlotX(x0);
                    int j0 = m_owner->GetClientCoordFromPlotY(y0);
                    int j1 = m_owner->GetClientCoordFromPlotY(y1);
                    wxPLOTCTRL_DRAW_LINE(dc, window, pen, i0, j0, i0, j1);
                }
            }
            else if ((marker_type == wxPLOTMARKER_HORIZ_LINE) || ((y0 == y1) && (x0 != x1)))
            {
                if (ClipLineToRect(x0, y0, x1, y1, subViewRect) != ClippedOut)
                {
                    int i0 = m_owner->GetClientCoordFromPlotX(x0);
                    int i1 = m_owner->GetClientCoordFromPlotX(x1);
                    int j0 = m_owner->GetClientCoordFromPlotY(y0);
                    wxPLOTCTRL_DRAW_LINE(dc, window, pen, i0, j0, i1, j0);
                }
            }
            else if ((marker_type == wxPLOTMARKER_CROSS) || cross)
            {


            }
            else                                // rectangle
            {
                wxRect2DDouble clippedRect(x0, y0, x1 - x0, y1 - y0);
                clippedRect.Intersect(subViewRect);
                int pen_width = dc->GetPen().GetWidth() + 2;

                int i0 = m_owner->GetClientCoordFromPlotX(clippedRect.m_x);
                int i1 = m_owner->GetClientCoordFromPlotX(clippedRect.GetRight());
                int j0 = m_owner->GetClientCoordFromPlotY(clippedRect.m_y);
                int j1 = m_owner->GetClientCoordFromPlotY(clippedRect.GetBottom());
                if (r.m_x < subViewRect.m_x)  i0 -= pen_width;
                if (r.m_y < subViewRect.m_y)  j0 -= pen_width;
                if (r.GetRight()  > subViewRect.GetRight())  i1 += pen_width;
                if (r.GetBottom() > subViewRect.GetBottom()) j1 += pen_width;

                dc->SetClippingRegion(dcRect);
                dc->DrawRectangle(i0, j0, i1 - i0 + 1, j1 - j0 + 1);
                dc->DestroyClippingRegion();
            }
        }
    }
}