Пример #1
0
/* CTexture::duplicatePatch
 * Duplicates the patch at [index], placing the duplicated patch
 * at [offset_x],[offset_y] from the original. Returns false if
 * [index] is out of bounds, true otherwise
 *******************************************************************/
bool CTexture::duplicatePatch(size_t index, int16_t offset_x, int16_t offset_y)
{
	// Check index
	if (index >= patches.size())
		return false;

	// Get patch info
	CTPatch* dp = patches[index];

	// Add duplicate patch
	if (extended)
		patches.insert(patches.begin() + index, new CTPatchEx((CTPatchEx*)patches[index]));
	else
		patches.insert(patches.begin() + index, new CTPatch(patches[index]));

	// Offset patch by given amount
	patches[index+1]->setOffsetX(dp->xOffset() + offset_x);
	patches[index+1]->setOffsetY(dp->yOffset() + offset_y);

	// Cannot be a simple define anymore
	this->defined = false;

	// Announce
	announce("patches_modified");

	return true;
}
Пример #2
0
/* CTexture::loadPatchImage
 * Loads the image for the patch at [pindex] into [image]. Can deal
 * with textures-as-patches
 *******************************************************************/
bool CTexture::loadPatchImage(unsigned pindex, SImage& image, Archive* parent, Palette8bit* pal)
{
	// Check patch index
	if (pindex >= patches.size())
		return false;

	CTPatch* patch = patches[pindex];

	// If the texture is extended, search for textures-as-patches first
	// (as long as the patch name is different from this texture's name)
	if (extended && !(S_CMPNOCASE(patch->getName(), name)))
	{
		// Search the texture list we're in first
		if (in_list)
		{
			for (unsigned a = 0; a < in_list->nTextures(); a++)
			{
				CTexture* tex = in_list->getTexture(a);

				// Don't look past this texture in the list
				if (tex->getName() == name)
					break;

				// Check for name match
				if (S_CMPNOCASE(tex->getName(), patch->getName()))
				{
					// Load texture to image
					return tex->toImage(image, parent, pal);
				}
			}
		}

		// Otherwise, try the resource manager
		// TODO: Something has to be ignored here. The entire archive or just the current list?
		CTexture* tex = theResourceManager->getTexture(patch->getName(), parent);
		if (tex)
			return tex->toImage(image, parent, pal);
	}

	// Get patch entry
	ArchiveEntry* entry = patch->getPatchEntry(parent);

	// Load entry to image if valid
	if (entry)
		return Misc::loadImageFromEntry(&image, entry);
	else
		return false;
}
Пример #3
0
/* TextureEditorPanel::onPatchPositionYChanged
 * Called when the patch y position spin control is changed
 *******************************************************************/
void TextureEditorPanel::onPatchPositionYChanged(wxCommandEvent& e)
{
	// If anything other than 1 patch is selected, do nothing (shouldn't happen anyway)
	if (list_patches->GetSelectedItemCount() != 1)
		return;

	// Get selected patch
	CTPatch* patch = tex_current->getPatch(list_patches->selectedItems()[0]);
	if (!patch) return;

	// Set patch y offset
	patch->setOffsetY(spin_patch_top->GetValue());

	// Update UI
	tex_canvas->redraw(true);

	tex_modified = true;
}
Пример #4
0
/* CTextureCanvas::patchAt
 * Returns the index of the patch at [x,y] on the texture, or -1
 * if no patch is at that position
 *******************************************************************/
int CTextureCanvas::patchAt(int x, int y)
{
	// Check a texture is open
	if (!texture)
		return -1;

	// Go through texture patches backwards (ie from frontmost to back)
	for (int a = texture->nPatches() - 1; a >= 0; a--)
	{
		// Check if x,y is within patch bounds
		CTPatch* patch = texture->getPatch(a);
		if (x >= patch->xOffset() && x < patch->xOffset() + (int)patch_textures[a]->getWidth() &&
		        y >= patch->yOffset() && y < patch->yOffset() + (int)patch_textures[a]->getHeight())
		{
			return a;
		}
	}

	// No patch at x,y
	return -1;
}
Пример #5
0
/* CTexture::copyTexture
 * Copies the texture [tex] to this texture. If keep_type is true,
 * the current texture type (extended/regular) will be kept,
 * otherwise it will be converted to the type of [tex]
 *******************************************************************/
void CTexture::copyTexture(CTexture* tex, bool keep_type)
{
	// Check texture was given
	if (!tex)
		return;

	// Clear current texture
	clear();

	// Copy texture info
	this->name = tex->name;
	this->width = tex->width;
	this->height = tex->height;
	this->scale_x = tex->scale_x;
	this->scale_y = tex->scale_y;
	this->world_panning = tex->world_panning;
	if (!keep_type) this->extended = tex->extended;
	this->optional = tex->optional;
	this->no_decals = tex->no_decals;
	this->null_texture = tex->null_texture;
	this->offset_x = tex->offset_x;
	this->offset_y = tex->offset_y;
	this->type = tex->type;

	// Copy patches
	for (unsigned a = 0; a < tex->nPatches(); a++)
	{
		CTPatch* patch = tex->getPatch(a);

		if (extended)
		{
			if (tex->extended)
				patches.push_back(new CTPatchEx((CTPatchEx*)patch));
			else
				patches.push_back(new CTPatchEx(patch));
		}
		else
			addPatch(patch->getName(), patch->xOffset(), patch->yOffset());
	}
}
Пример #6
0
/* TextureEditorPanel::updatePatchControls
 * Updates all patch editing controls with values from the currently
 * selected patch. Behaves differently depending on the number of
 * patches selected
 *******************************************************************/
void TextureEditorPanel::updatePatchControls()
{
	// Get selected patches
	wxArrayInt selection = list_patches->selectedItems();

	// If nothing is selected, disable patch controls
	if (selection.size() == 0)
	{
		spin_patch_left->Enable(false);
		spin_patch_top->Enable(false);
	}
	else
	{
		// Something is selected, enable the controls
		spin_patch_left->Enable(true);
		spin_patch_top->Enable(true);

		// If only 1 patch is selected, just set the controls to this patch
		if (selection.size() == 1)
		{
			CTPatch* patch = tex_current->getPatch(selection[0]);
			if (!patch)
			{
				wxLogMessage("Error: Selected patch does not exist in texture");
				return;
			}

			spin_patch_left->SetValue(patch->xOffset());
			spin_patch_top->SetValue(patch->yOffset());
		}
		else
		{
			// Multiple selection, only enable some controls
			spin_patch_left->Enable(false);
			spin_patch_top->Enable(false);
		}
	}
}
Пример #7
0
/* TextureXPanel::paste
 * Pastes any textures on the clipboard after the last selected
 * texture
 *******************************************************************/
void TextureXPanel::paste()
{
	// Check there is anything on the clipboard
	if (theClipboard->nItems() == 0)
		return;

	// Get last selected index
	int selected = list_textures->getLastSelected();
	if (selected == -1) selected = texturex.nTextures() - 1; // Add to end of the list if nothing selected

	// Begin recording undo level
	undo_manager->beginRecord("Paste Texture(s)");

	// Go through clipboard items
	for (unsigned a = 0; a < theClipboard->nItems(); a++)
	{
		// Skip if not a texture clipboard item
		if (theClipboard->getItem(a)->getType() != CLIPBOARD_COMPOSITE_TEXTURE)
			continue;

		// Get texture item
		TextureClipboardItem* item = (TextureClipboardItem*)(theClipboard->getItem(a));

		// Add new texture after last selected item
		CTexture* ntex = new CTexture((texturex.getFormat() == TXF_TEXTURES));
		ntex->copyTexture(item->getTexture(), true);
		ntex->setState(2);
		texturex.addTexture(ntex, ++selected);

		// Record undo step
		undo_manager->recordUndoStep(new TextureCreateDeleteUS(this, ntex, true));

		// Deal with patches
		for (unsigned p = 0; p < ntex->nPatches(); p++)
		{
			CTPatch* patch = ntex->getPatch(p);

			// Update patch table if necessary
			if (texturex.getFormat() != TXF_TEXTURES)
				tx_editor->patchTable().addPatch(patch->getName());

			// Get the entry for this patch
			ArchiveEntry* entry = patch->getPatchEntry(tx_editor->getArchive());

			// If the entry wasn't found in any open archive, try copying it from the clipboard
			// (the user may have closed the archive the original patch was in)
			if (!entry)
			{
				entry = item->getPatchEntry(patch->getName());

				// Copy the copied patch entry over to this archive
				if (entry)
					tx_editor->getArchive()->addEntry(entry, "patches", true);
			}

			// If the entry exists in the base resource archive or this archive, do nothing
			else if (entry->getParent() == theArchiveManager->baseResourceArchive() ||
			         entry->getParent() == tx_editor->getArchive())
				continue;

			// Otherwise, copy the entry over to this archive
			else
				tx_editor->getArchive()->addEntry(entry, "patches", true);
		}
	}

	// End recording undo level
	undo_manager->endRecord(true);

	// Refresh
	list_textures->updateList();

	// Update variables
	modified = true;
}
Пример #8
0
/* TextureEditorPanel::onTexCanvasKeyDown
 * Called when a key is pressed within the texture canvas
 *******************************************************************/
void TextureEditorPanel::onTexCanvasKeyDown(wxKeyEvent& e)
{
	// Check if keypress matches any keybinds
	wxArrayString binds = KeyBind::getBinds(KeyBind::asKeyPress(e.GetKeyCode(), e.GetModifiers()));

	// Check for alt key
	if (e.GetKeyCode() == WXK_ALT)
		alt_press = true;

	// Go through matching binds
	int x_movement = 0;
	int y_movement = 0;
	bool handled = false;
	for (unsigned a = 0; a < binds.size(); a++)
	{
		string name = binds[a];

		// Move patch left
		if (name == "txed_patch_left")
			x_movement = -1;
		else if (name == "txed_patch_left8")
			x_movement = -8;

		// Move patch up
		else if (name == "txed_patch_up")
			y_movement = -1;
		else if (name == "txed_patch_up8")
			y_movement = -8;

		// Move patch right
		else if (name == "txed_patch_right")
			x_movement = 1;
		else if (name == "txed_patch_right8")
			x_movement = 8;

		// Move patch down
		else if (name == "txed_patch_down")
			y_movement = 1;
		else if (name == "txed_patch_down8")
			y_movement = 8;

		// Add patch
		else if (name == "txed_patch_add")
		{
			hack_nodrag = true;
			addPatch();
			handled = true;
		}

		// Delete patch
		else if (name == "txed_patch_delete")
		{
			removePatch();
			handled = true;
		}

		// Replace patch
		else if (name == "txed_patch_replace")
		{
			hack_nodrag = true;
			replacePatch();
			handled = true;
		}

		// Duplicate patch
		else if (name == "txed_patch_duplicate")
		{
			duplicatePatch();
			handled = true;
		}

		// Bring patch forward
		else if (name == "txed_patch_forward")
		{
			patchForward();
			handled = true;
		}

		// Send patch back
		else if (name == "txed_patch_back")
		{
			patchBack();
			handled = true;
		}
	}

	// Move patches if needed
	if (x_movement != 0 || y_movement != 0)
	{
		// Do patch duplicate if alt is pressed
		if (e.GetModifiers() == wxMOD_ALT && alt_press)
		{
			duplicatePatch(0, 0);
			alt_press = false;
		}

		wxArrayInt selected_patches = list_patches->selectedItems();
		for (size_t a = 0; a < selected_patches.size(); a++)
		{
			CTPatch* patch = tex_current->getPatch(selected_patches[a]);
			if (!patch) continue;
			int16_t cx = patch->xOffset();
			int16_t cy = patch->yOffset();
			patch->setOffsetX(cx + x_movement);
			patch->setOffsetY(cy + y_movement);
			tex_modified = true;
		}

		tex_canvas->redraw(true);
		handled = true;
	}

	if (!e.AltDown())
		alt_press = false;

	if (!handled)
		e.Skip();
}
Пример #9
0
/* TextureEditorPanel::onTexCanvasMouseEvent
 * Called on any mouse event within the texture canvas
 *******************************************************************/
void TextureEditorPanel::onTexCanvasMouseEvent(wxMouseEvent& e)
{
	// Get mouse position relative to texture
	point2_t pos = tex_canvas->screenToTexPosition(e.GetX(), e.GetY());

	// Get patch that the mouse is over (if any)
	int patch = tex_canvas->patchAt(pos.x, pos.y);

	// LEFT DOUBLE CLICK
	if (e.ButtonDClick(wxMOUSE_BTN_LEFT))
	{
		replacePatch();
	}

	// LEFT MOUSE DOWN
	else if (e.LeftDown())
	{
		// If not dragging
		if (e.ShiftDown())
		{
			// Shift is down, add to selection
			if (patch >= 0)
				list_patches->selectItem(patch);
		}
		else if (e.ControlDown())
		{
			// Control is down, remove from selection
			if (patch >= 0)
				list_patches->deSelectItem(patch);
		}
		else
		{
			// Clear selection only if patch clicked was not already selected
			if (!tex_canvas->patchSelected(patch))
				list_patches->clearSelection();

			// Select patch
			if (patch >= 0)
				list_patches->selectItem(patch);
		}
	}

	// LEFT MOUSE UP
	else if (e.LeftUp())
	{
		// Hide texture grid
		tex_canvas->showGrid(false);

		// If mouse up over an already-selected patch, and shift/ctrl aren't down,
		// select only that patch (this mimics 'normal' drag-and-drop/selection behaviour)
		if (!e.ShiftDown() && !e.ControlDown() && tex_canvas->patchSelected(patch) && !tex_canvas->isDragging())
		{
			list_patches->clearSelection();
			list_patches->selectItem(patch);
		}

		// Redraw texture canvas
		tex_canvas->redraw(false);
		updateTextureControls();
	}

	// RIGHT MOUSE UP
	else if (e.RightUp())
	{
		// Create context menu
		wxMenu popup;
		theApp->getAction("txed_patch_add")->addToMenu(&popup, true);
		theApp->getAction("txed_patch_remove")->addToMenu(&popup, true);
		theApp->getAction("txed_patch_replace")->addToMenu(&popup, true);
		theApp->getAction("txed_patch_back")->addToMenu(&popup, true);
		theApp->getAction("txed_patch_forward")->addToMenu(&popup, true);
		theApp->getAction("txed_patch_duplicate")->addToMenu(&popup, true);

		hack_nodrag = true;
		PopupMenu(&popup);
	}

	// MOUSE DRAGGING
	else if (e.Dragging())
	{
		// Drag selected patches if left button is down and any patch is selected
		if (hack_nodrag)
			hack_nodrag = false;
		else if (e.LeftIsDown())
		{
			if (list_patches->GetSelectedItemCount() > 0)
			{
				// Get drag amount according to texture
				point2_t tex_cur = tex_canvas->screenToTexPosition(e.GetX(), e.GetY());
				point2_t tex_prev = tex_canvas->screenToTexPosition(tex_canvas->getMousePrevPos().x, tex_canvas->getMousePrevPos().y);
				point2_t diff = tex_cur - tex_prev;

				// Move any selected patches
				wxArrayInt selected_patches = list_patches->selectedItems();
				for (size_t a = 0; a < selected_patches.size(); a++)
				{
					CTPatch* patch = tex_current->getPatch(selected_patches[a]);
					if (!patch) continue;
					int16_t cx = patch->xOffset();
					int16_t cy = patch->yOffset();
					patch->setOffsetX(cx + diff.x);
					patch->setOffsetY(cy + diff.y);
					tex_modified = true;
				}

				// Refresh texture canvas
				tex_canvas->showGrid(true);
				tex_canvas->redraw(false);
			}
			else if (tex_current && tex_current->isExtended() && tex_canvas->getViewType() > 0)
			{
				// Get drag amount according to texture
				point2_t tex_cur = tex_canvas->screenToTexPosition(e.GetX(), e.GetY());
				point2_t tex_prev = tex_canvas->screenToTexPosition(tex_canvas->getMousePrevPos().x, tex_canvas->getMousePrevPos().y);
				point2_t diff = tex_cur - tex_prev;

				// Modify offsets
				tex_current->setOffsetX(tex_current->getOffsetX() - diff.x);
				tex_current->setOffsetY(tex_current->getOffsetY() - diff.y);
				tex_modified = true;

				// Refresh texture canvas
				tex_canvas->redraw(false);
			}
		}
	}

	e.Skip();
}
Пример #10
0
/* TextureXList::writeTEXTUREXData
 * Writes the texture list in TEXTUREX format to [texturex], using
 * [patch_table] for patch information. Returns true on success,
 * false otherwise
 *******************************************************************/
bool TextureXList::writeTEXTUREXData(ArchiveEntry* texturex, PatchTable& patch_table) {
	// Check entry was given
	if (!texturex)
		return false;

	if (texturex->isLocked())
		return false;

	wxLogMessage("Writing " + getTextureXFormatString() + " format TEXTUREx entry");

	/* Total size of a TEXTUREx lump, in bytes:
		Header: 4 + (4 * numtextures)
		Textures:
			22 * numtextures (normal format)
			14 * numtextures (nameless format)
			18 * numtextures (Strife 1.1 format)
		Patches:
			10 * sum of patchcounts (normal and nameless formats)
			 6 * sum of patchcounts (Strife 1.1 format)
	*/
	size_t numpatchrefs = 0;
	size_t numtextures = textures.size();
	for (size_t i = 0; i < numtextures; ++i) {
		numpatchrefs += textures[i]->nPatches();
	}
	wxLogMessage("%i patch references in %i textures", numpatchrefs, numtextures);

	size_t datasize = 0;
	size_t headersize = 4 + (4 * numtextures);
	switch (txformat) {
		case TXF_NORMAL:	datasize = 4 + (26 * numtextures) + (10 * numpatchrefs); break;
		case TXF_NAMELESS:	datasize = 4 + (18 * numtextures) + (10 * numpatchrefs); break;
		case TXF_STRIFE11:	datasize = 4 + (22 * numtextures) + ( 6 * numpatchrefs); break;
		// Some compilers insist on having default cases.
		default: return false;
	}

	MemChunk txdata(datasize);
	int32_t* offsets = new int32_t[numtextures];
	int32_t foo = wxINT32_SWAP_ON_BE((signed) numtextures);

	// Write header
	txdata.seek(0, SEEK_SET);
	SAFEFUNC(txdata.write(&foo, 4));

	// Go to beginning of texture definitions
	SAFEFUNC(txdata.seek(4 + (numtextures*4), SEEK_SET));

	// Write texture entries
	for (size_t i = 0; i < numtextures; ++i) {
		// Get texture to write
		CTexture* tex = textures[i];

		// Set offset
		offsets[i] = (signed)txdata.currentPos();

		// Write texture entry
		switch (txformat) {
			case TXF_NORMAL:
			{
				// Create 'normal' doom format texture definition
				ftdef_t txdef;
				memset(txdef.name, 0, 8); // Set texture name to all 0's (to ensure compatibility with XWE)
				strncpy(txdef.name, CHR(tex->getName().Upper()), tex->getName().Len());
				txdef.flags			= 0;
				txdef.scale[0]		= (tex->getScaleX()*8);
				txdef.scale[1]		= (tex->getScaleY()*8);
				txdef.width			= tex->getWidth();
				txdef.height		= tex->getHeight();
				txdef.columndir[0]	= 0;
				txdef.columndir[1]	= 0;
				txdef.patchcount	= tex->nPatches();

				// Check for WorldPanning flag
				if (tex->world_panning)
					txdef.flags |= TX_WORLDPANNING;

				// Write texture definition
				SAFEFUNC(txdata.write(&txdef, 22));

				break;
			}
			case TXF_NAMELESS:
			{
				// Create nameless texture definition
				nltdef_t txdef;
				txdef.flags			= 0;
				txdef.scale[0]		= (tex->getScaleX()*8);
				txdef.scale[1]		= (tex->getScaleY()*8);
				txdef.width			= tex->getWidth();
				txdef.height		= tex->getHeight();
				txdef.columndir[0]	= 0;
				txdef.columndir[1]	= 0;
				txdef.patchcount	= tex->nPatches();

				// Write texture definition
				SAFEFUNC(txdata.write(&txdef, 8));

				break;
			}
			case TXF_STRIFE11:
			{
				// Create strife format texture definition
				stdef_t txdef;
				memset(txdef.name, 0, 8); // Set texture name to all 0's (to ensure compatibility with XWE)
				strncpy(txdef.name, CHR(tex->getName().Upper()), tex->getName().Len());
				txdef.flags			= 0;
				txdef.scale[0]		= (tex->getScaleX()*8);
				txdef.scale[1]		= (tex->getScaleY()*8);
				txdef.width			= tex->getWidth();
				txdef.height		= tex->getHeight();
				txdef.patchcount	= tex->nPatches();

				// Check for WorldPanning flag
				if (tex->world_panning)
					txdef.flags |= TX_WORLDPANNING;

				// Write texture definition
				SAFEFUNC(txdata.write(&txdef, 18));

				break;
			}
			default: return false;
		}

		// Write patch references
		for (size_t k = 0; k < tex->nPatches(); ++k) {
			// Get patch to write
			CTPatch* patch = tex->getPatch(k);

			// Create patch definition
			tx_patch_t pdef;
			pdef.left = patch->xOffset();
			pdef.top = patch->yOffset();

			// Check for 'invalid' patch
			if (patch->getName().StartsWith("INVPATCH")) {
				// Get raw patch index from name
				string number = patch->getName();
				number.Replace("INVPATCH", "");
				long index;
				number.ToLong(&index);
				pdef.patch = index;
			}
			else
				pdef.patch = patch_table.patchIndex(patch->getName());	// Note this will be -1 if the patch doesn't exist in the patch table. This should never happen with the texture editor, though.

			// Write common data
			SAFEFUNC(txdata.write(&pdef, 6));

			// In non-Strife formats, there's some added rubbish
			if (txformat != TXF_STRIFE11) {
				foo = 0;
				SAFEFUNC(txdata.write(&foo, 4));
			}
		}
	}

	// Write offsets
	SAFEFUNC(txdata.seek(4, SEEK_SET));
	SAFEFUNC(txdata.write(offsets, 4*numtextures));

	// Write data to the TEXTUREx entry
	texturex->importMemChunk(txdata);

	// Update entry type
	EntryType::detectEntryType(texturex);

	// Clean up
	delete[] offsets;

	return true;
}
Пример #11
0
/* CTexture::toImage
 * Generates a SImage representation of this texture, using patches
 * from [parent] primarily, and the palette [pal]
 *******************************************************************/
bool CTexture::toImage(SImage& image, Archive* parent, Palette8bit* pal, bool force_rgba)
{
	// Init image
	image.clear();
	image.resize(width, height);

	// Add patches
	SImage p_img(PALMASK);
	si_drawprops_t dp;
	dp.src_alpha = false;
	if (defined)
	{
		CTPatchEx* patch = (CTPatchEx*)patches[0];
		if (!loadPatchImage(0, p_img, parent, pal))
			return false;
		width = p_img.getWidth();
		height = p_img.getHeight();
		image.resize(width, height);
		scale_x = (double)width / (double)def_width;
		scale_y = (double)height / (double)def_height;
		image.drawImage(p_img, 0, 0, dp, pal, pal);
	}
	else if (extended)
	{
		// Extended texture

		// Add each patch to image
		for (unsigned a = 0; a < patches.size(); a++)
		{
			CTPatchEx* patch = (CTPatchEx*)patches[a];

			// Load patch entry
			if (!loadPatchImage(a, p_img, parent, pal))
				continue;

			// Handle offsets
			int ofs_x = patch->xOffset();
			int ofs_y = patch->yOffset();
			if (patch->useOffsets())
			{
				ofs_x -= p_img.offset().x;
				ofs_y -= p_img.offset().y;
			}

			// Apply translation before anything in case we're forcing rgba (can't translate rgba images)
			if (patch->getBlendType() == 1)
				p_img.applyTranslation(&(patch->getTranslation()), pal);

			// Convert to RGBA if forced
			if (force_rgba)
				p_img.convertRGBA(pal);

			// Flip/rotate if needed
			if (patch->flipX())
				p_img.mirror(false);
			if (patch->flipY())
				p_img.mirror(true);
			if (patch->getRotation() != 0)
				p_img.rotate(patch->getRotation());

			// Setup transparency blending
			dp.blend = NORMAL;
			dp.alpha = 1.0f;
			dp.src_alpha = false;
			if (patch->getStyle() == "CopyAlpha" || patch->getStyle() == "Overlay")
				dp.src_alpha = true;
			else if (patch->getStyle() == "Translucent" || patch->getStyle() == "CopyNewAlpha")
				dp.alpha = patch->getAlpha();
			else if (patch->getStyle() == "Add")
			{
				dp.blend = ADD;
				dp.alpha = patch->getAlpha();
			}
			else if (patch->getStyle() == "Subtract")
			{
				dp.blend = SUBTRACT;
				dp.alpha = patch->getAlpha();
			}
			else if (patch->getStyle() == "ReverseSubtract")
			{
				dp.blend = REVERSE_SUBTRACT;
				dp.alpha = patch->getAlpha();
			}
			else if (patch->getStyle() == "Modulate")
			{
				dp.blend = MODULATE;
				dp.alpha = patch->getAlpha();
			}

			// Setup patch colour
			if (patch->getBlendType() == 2)
				p_img.colourise(patch->getColour(), pal);
			else if (patch->getBlendType() == 3)
				p_img.tint(patch->getColour(), patch->getColour().fa(), pal);


			// Add patch to texture image
			image.drawImage(p_img, ofs_x, ofs_y, dp, pal, pal);
		}
	}
	else
	{
		// Normal texture

		// Add each patch to image
		for (unsigned a = 0; a < patches.size(); a++)
		{
			CTPatch* patch = patches[a];
			if (Misc::loadImageFromEntry(&p_img, patch->getPatchEntry(parent)))
				image.drawImage(p_img, patch->xOffset(), patch->yOffset(), dp, pal, pal);
		}
	}

	return true;
}
Пример #12
0
/* CTextureCanvas::drawPatch
 * Draws the patch at index [num] in the composite texture
 *******************************************************************/
void CTextureCanvas::drawPatch(int num, bool outside)
{
	// Get patch to draw
	CTPatch* patch = texture->getPatch(num);

	// Check it exists
	if (!patch)
		return;

	// Load the patch as an opengl texture if it isn't already
	if (!patch_textures[num]->isLoaded())
	{
		SImage temp(PALMASK);
		if (texture->loadPatchImage(num, temp, parent, &palette))
		{
			// Load the image as a texture
			patch_textures[num]->loadImage(&temp, &palette);
		}
		else
			patch_textures[num]->genChequeredTexture(8, COL_RED, COL_BLACK);
	}

	// Translate to position
	glPushMatrix();
	glTranslated(patch->xOffset(), patch->yOffset(), 0);

	// Setup rendering options
	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

	// Setup extended features
	bool flipx = false;
	bool flipy = false;
	double alpha = 1.0;
	bool shade_select = true;
	rgba_t col = COL_WHITE;
	if (texture->isExtended())
	{
		// Get extended patch
		CTPatchEx* epatch = (CTPatchEx*)patch;

		// Flips
		if (epatch->flipX())
			flipx = true;
		if (epatch->flipY())
			flipy = true;

		// Rotation
		if (epatch->getRotation() == 90)
		{
			glTranslated(patch_textures[num]->getHeight(), 0, 0);
			glRotated(90, 0, 0, 1);
		}
		else if (epatch->getRotation() == 180)
		{
			glTranslated(patch_textures[num]->getWidth(), patch_textures[num]->getHeight(), 0);
			glRotated(180, 0, 0, 1);
		}
		else if (epatch->getRotation() == -90)
		{
			glTranslated(0, patch_textures[num]->getWidth(), 0);
			glRotated(-90, 0, 0, 1);
		}
	}

	// Set colour
	if (outside)
		glColor4f(0.8f, 0.2f, 0.2f, 0.3f);
	else
		glColor4f(col.fr(), col.fg(), col.fb(), alpha);

	// Draw the patch
	patch_textures[num]->draw2d(0, 0, flipx, flipy);

	glPopMatrix();
}
Пример #13
0
/* CTextureCanvas::drawTexture
 * Draws the currently opened composite texture
 *******************************************************************/
void CTextureCanvas::drawTexture()
{
	// Push matrix
	glPushMatrix();

	// Calculate top-left position of texture (for glScissor, since it ignores the current translation/scale)
	double left = offset.x + (GetSize().x * 0.5) - (texture->getWidth() * 0.5 * scale);
	double top = -offset.y + (GetSize().y * 0.5) - (texture->getHeight() * 0.5 * scale);

	// Translate to middle of the canvas
	glTranslated(GetSize().x * 0.5, GetSize().y * 0.5, 0);

	// Zoom
	double yscale = (tx_arc ? scale * 1.2 : scale);
	glScaled(scale, yscale, 1);

	// Draw offset guides if needed
	drawOffsetLines();

	// Apply texture scale
	double tscalex = 1;
	double tscaley = 1;
	if (tex_scale)
	{
		tscalex = texture->getScaleX();
		if (tscalex == 0) tscalex = 1;
		tscaley = texture->getScaleY();
		if (tscaley == 0) tscaley = 1;
		glScaled(1.0 / tscalex, 1.0 / tscaley, 1);
	}

	// Translate by offsets if needed
	if (view_type == 0)
		glTranslated(texture->getWidth() * -0.5, texture->getHeight() * -0.5, 0);	// No offsets
	if (view_type >= 1)
		glTranslated(-texture->getOffsetX(), -texture->getOffsetY(), 0);			// Sprite offsets
	if (view_type == 2)
		glTranslated(-160*tscalex, -100*tscaley, 0);								// HUD offsets

	// Draw the texture border
	//if (gfx_show_border)
	drawTextureBorder();

	// Enable textures
	glEnable(GL_TEXTURE_2D);

	// First, draw patches semitransparently (for anything outside the texture)
	// But only if we are drawing stuff outside the texture area
	if (draw_outside)
	{
		for (uint32_t a = 0; a < texture->nPatches(); a++)
			drawPatch(a, true);
	}

	// Reset colouring
	OpenGL::setColour(COL_WHITE);

	// If we're currently dragging, draw a 'basic' preview of the texture using opengl
	if (dragging)
	{
		glEnable(GL_SCISSOR_TEST);
		glScissor(left, top, texture->getWidth() * scale, texture->getHeight() * scale);
		for (uint32_t a = 0; a < texture->nPatches(); a++)
			drawPatch(a);
		glDisable(GL_SCISSOR_TEST);
	}

	// Otherwise, draw the fully generated texture
	else
	{
		// Generate if needed
		if (!tex_preview.isLoaded())
		{
			// Determine image type
			SIType type = PALMASK;
			if (blend_rgba) type = RGBA;

			// CTexture -> temp Image -> GLTexture
			SImage temp(type);
			texture->toImage(temp, parent, &palette, blend_rgba);
			tex_preview.loadImage(&temp, &palette);
		}

		// Draw it
		tex_preview.draw2d();
	}

	// Disable textures
	glDisable(GL_TEXTURE_2D);

	// Now loop through selected patches and draw selection outlines
	OpenGL::setColour(70, 210, 220, 255, BLEND_NORMAL);
	glEnable(GL_LINE_SMOOTH);
	glLineWidth(1.5f);
	for (size_t a = 0; a < selected_patches.size(); a++)
	{
		// Skip if not selected
		if (!selected_patches[a])
			continue;

		// Get patch
		CTPatch* patch = texture->getPatch(a);
		CTPatchEx* epatch = (CTPatchEx*)patch;

		// Check for rotation
		if (texture->isExtended() && (epatch->getRotation() == 90 || epatch->getRotation() == -90))
		{
			// Draw outline, width/height swapped
			glBegin(GL_LINE_LOOP);
			glVertex2i(patch->xOffset(), patch->yOffset());
			glVertex2i(patch->xOffset(), patch->yOffset() + (int)patch_textures[a]->getWidth());
			glVertex2i(patch->xOffset() + (int)patch_textures[a]->getHeight(), patch->yOffset() + (int)patch_textures[a]->getWidth());
			glVertex2i(patch->xOffset() + (int)patch_textures[a]->getHeight(), patch->yOffset());
			glEnd();
		}
		else
		{
			// Draw outline
			glBegin(GL_LINE_LOOP);
			glVertex2i(patch->xOffset(), patch->yOffset());
			glVertex2i(patch->xOffset(), patch->yOffset() + (int)patch_textures[a]->getHeight());
			glVertex2i(patch->xOffset() + (int)patch_textures[a]->getWidth(), patch->yOffset() + (int)patch_textures[a]->getHeight());
			glVertex2i(patch->xOffset() + (int)patch_textures[a]->getWidth(), patch->yOffset());
			glEnd();
		}
	}

	// Finally, draw a hilight outline if anything is hilighted
	if (hilight_patch >= 0)
	{
		// Set colour
		OpenGL::setColour(255, 255, 255, 150, BLEND_ADDITIVE);

		// Get patch
		CTPatch* patch = texture->getPatch(hilight_patch);
		CTPatchEx* epatch = (CTPatchEx*)patch;
		GLTexture* patch_texture = patch_textures[hilight_patch];

		// Check for rotation
		if (texture->isExtended() && (epatch->getRotation() == 90 || epatch->getRotation() == -90))
		{
			// Draw outline, width/height swapped
			glBegin(GL_LINE_LOOP);
			glVertex2i(patch->xOffset(), patch->yOffset());
			glVertex2i(patch->xOffset(), patch->yOffset() + (int)patch_texture->getWidth());
			glVertex2i(patch->xOffset() + (int)patch_texture->getHeight(), patch->yOffset() + (int)patch_texture->getWidth());
			glVertex2i(patch->xOffset() + (int)patch_texture->getHeight(), patch->yOffset());
			glEnd();
		}
		else
		{
			// Draw outline
			glBegin(GL_LINE_LOOP);
			glVertex2i(patch->xOffset(), patch->yOffset());
			glVertex2i(patch->xOffset(), patch->yOffset() + (int)patch_texture->getHeight());
			glVertex2i(patch->xOffset() + (int)patch_texture->getWidth(), patch->yOffset() + (int)patch_texture->getHeight());
			glVertex2i(patch->xOffset() + (int)patch_texture->getWidth(), patch->yOffset());
			glEnd();
		}
	}
	glDisable(GL_LINE_SMOOTH);
	glLineWidth(1.0f);

	// Pop matrix
	glPopMatrix();
}