Example #1
0
//------------------------------------------------------------------------------
//!
bool
ParticleGeometry::updateRenderData()
{
   CHECK( _rgeom.isValid() );
   CHECK( _rgeom->numBuffers() >= 1 );
   CHECK( _entity );

   const RCP<Gfx::VertexBuffer>& buffer = _rgeom->buffers()[0];
   const ParticleData& data = _entity->data();

   //data.print();
   //getchar();

   size_t s = data.size() * data.vertexStride() * sizeof(float);

   float* dst = (float*)Core::gfx()->map( buffer, Gfx::MAP_WRITE, 0, s );
   if( dst )
   {
      memcpy( dst, data.vertexData(), s );
      Core::gfx()->unmap( buffer );
      clearPatches();
      addPatch( 0, data.size(), 0 );
      return true;
   }
   else
   {
      CHECK( dst != NULL );
      return false;
   }
}
Example #2
0
USING_NAMESPACE

/*==============================================================================
  UNNAMED NAMESPACE
==============================================================================*/
UNNAMESPACE_BEGIN



UNNAMESPACE_END


/*==============================================================================
  CLASS ParticleGeometry
==============================================================================*/

//------------------------------------------------------------------------------
//!
ParticleGeometry::ParticleGeometry( ParticleEntity* e ):
   Geometry( Geometry::PARTICLE ),
   _entity( e )
{
   // Fake a patch to avoid culling in Renderer::classifyEntities().
   addPatch( 0, 0, 0 );
}
Example #3
0
void TextureLumpArea::onAddPatch(wxCommandEvent &event)
{
	if (list_textures->GetSelection() == -1 ||
		list_pnames->GetSelection() == -1)
		return;

	addPatch(list_pnames->GetSelection());
}
Example #4
0
// -----------------------------------------------------------------------------
// Loads a PNAMES entry, returns true on success, false otherwise
// -----------------------------------------------------------------------------
bool PatchTable::loadPNAMES(ArchiveEntry* pnames, Archive* parent)
{
	// Check entry was given
	if (!pnames)
		return false;

	// Mute while loading
	setMuted(true);

	// Clear current table
	patches_.clear();

	// Setup parent archive
	if (!parent)
		parent = pnames->parent();

	// Read number of pnames
	uint32_t n_pnames = 0;
	pnames->seek(0, SEEK_SET);
	if (!pnames->read(&n_pnames, 4))
	{
		Log::error("PNAMES lump is corrupt");
		return false;
	}

	// Read pnames content
	for (uint32_t a = 0; a < n_pnames; a++)
	{
		char pname[9] = "";
		pname[8]      = 0;

		// Try to read pname
		if (!pnames->read(&pname, 8))
		{
			Log::error("PNAMES entry {} is corrupt", a);
			return false;
		}

		// Add new patch
		addPatch(StrUtil::upper(pname), true);
	}

	// Update variables
	parent_ = parent;
	setMuted(false);

	// Announce
	announce("modified");

	return true;
}
Example #5
0
/* TextureEditorPanel::handleAction
 * Handles the action [id]. Returns true if the action was handled,
 * false otherwise
 *******************************************************************/
bool TextureEditorPanel::handleAction(string id)
{
	// Don't handle actions if hidden
	if (!IsShown())
		return false;

	// Only interested in actions beginning with txed_
	if (!id.StartsWith("txed_"))
		return false;

	// Add Patch
	if (id == "txed_patch_add")
		addPatch();

	// Remove Patch
	else if (id == "txed_patch_remove")
		removePatch();

	// Send Patch Back
	else if (id == "txed_patch_back")
		patchBack();

	// Bring Patch Forward
	else if (id == "txed_patch_forward")
		patchForward();

	// Replace Patch
	else if (id == "txed_patch_replace")
		replacePatch();

	// Duplicate Patch
	else if (id == "txed_patch_duplicate")
		duplicatePatch();

	// Unknown action
	else
		return false;

	// Action was handled
	return true;
}
Example #6
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());
	}
}
Example #7
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();
}
Example #8
0
/* TextureEditorPanel::onBtnPatchAdd
 * Called when the 'add patch' button is pressed
 *******************************************************************/
void TextureEditorPanel::onBtnPatchAdd(wxCommandEvent& e)
{
	addPatch();
}
Example #9
0
void Rig::loadPatches(JSONNode root) {
  JSONNode::iterator i = root.begin();

  // for this we want to iterate through all children and have the device class
  // parse the sub-element.
  while (i != root.end()){
	if (i->name() == "jsonPath") {
		i++;
		continue;
	}

    // get the node name and value as a string
    std::string nodeName = i->name();

    stringstream ss;
    ss << "Loading patch " << nodeName;
    Logger::log(INFO, ss.str());

    Patch* patch;
    
    auto type = i->find("type");
    if (type == i->end()) {
      stringstream ss;
      ss << "Unable to determine Patch type for " << nodeName << ". Patch not loaded.";
      Logger::log(WARN, ss.str());
    }

    string patchType = type->as_string();

    // New patch types will need new seralization definitions.
    if (patchType == "DMXPatch") {
      patch = (Patch*) new DMXPatch(*i);
      addPatch(nodeName, patch);
    }
#ifdef USE_ARNOLD
	else if (patchType == "PhotoPatch") {
		patch = (Patch*) new PhotoPatch(*i);
		addPatch(nodeName, patch);

		Device::DeviceCallbackFunction callback = std::bind(&PhotoPatch::onDeviceChanged,
			(PhotoPatch*)patch,
			std::placeholders::_1);
		for (Device *d : getDeviceRaw()) {
			d->addParameterChangedCallback(callback);
			d->addMetadataChangedCallback(callback);
		}
	}
	else if (patchType == "PhotoAnimationPatch") {
		patch = (Patch*) new PhotoAnimationPatch(*i);
		addPatch(nodeName, patch);

		Device::DeviceCallbackFunction callback = std::bind(&PhotoAnimationPatch::onDeviceChanged,
			(PhotoAnimationPatch*)patch,
			std::placeholders::_1);
		for (Device *d : getDeviceRaw()) {
			d->addParameterChangedCallback(callback);
			d->addMetadataChangedCallback(callback);
		}
	}
    else if (patchType == "ArnoldAnimationPatch") {
	  i->push_back(*root.find("jsonPath"));
      patch = (Patch*) new ArnoldAnimationPatch(*i);
      addPatch(nodeName, patch);
      Device::DeviceCallbackFunction callback = std::bind(&ArnoldAnimationPatch::onDeviceChanged,
                                                            (ArnoldAnimationPatch*)patch,
                                                            std::placeholders::_1);
      for (Device *d : getDeviceRaw()) {
          d->addParameterChangedCallback(callback);
          d->addMetadataChangedCallback(callback);
      }
    }
    else if (patchType == "ArnoldPatch") {
	  i->push_back(*i->find("jsonPath"));
      patch = (Patch*) new ArnoldPatch(*i);
      addPatch(nodeName, patch);
        
        Device::DeviceCallbackFunction callback = std::bind(&ArnoldPatch::onDeviceChanged,
                                                            (ArnoldPatch*)patch,
                                                            std::placeholders::_1);
        for (Device *d : getDeviceRaw()) {
            d->addParameterChangedCallback(callback);
            d->addMetadataChangedCallback(callback);
        }
    }
#endif
    else {
      stringstream ss;
      ss << "Unknown Patch type " << patchType << " in Patch ID " << nodeName << "Patch not loaded.";
      Logger::log(WARN, ss.str());
    }

    //increment the iterator
    ++i;
  }
}
Example #10
0
// -----------------------------------------------------------------------------
// Static function to check if an archive has sufficient texture related
// entries, and if not, prompts the user to either create or import them.
// Returns true if the entries exist, false otherwise
// -----------------------------------------------------------------------------
bool TextureXEditor::setupTextureEntries(Archive* archive)
{
	using Format = TextureXList::Format;

	// Check any archive was given
	if (!archive)
		return false;

	// Search archive for any ZDoom TEXTURES entries
	Archive::SearchOptions options;
	options.match_type = EntryType::fromId("zdtextures");
	auto entry_tx      = archive->findFirst(options); // Find any TEXTURES entry

	// If it's found, we're done
	if (entry_tx)
		return true;


	// Search archive for any texture-related entries
	options.match_type = EntryType::fromId("texturex");
	entry_tx           = archive->findFirst(options); // Find any TEXTUREx entry
	options.match_type = EntryType::fromId("pnames");
	auto entry_pnames  = archive->findFirst(options); // Find any PNAMES entry

	// If both exist, we're done
	if (entry_tx && entry_pnames)
		return true;

	// Todo: accept entry_tx without pnames if the textures are in Jaguar mode

	// If no TEXTUREx entry exists
	if (!entry_tx)
	{
		// No TEXTUREx entries found, so ask if the user wishes to create one
		wxMessageDialog dlg(
			nullptr,
			"The archive does not contain any texture definitions (TEXTURE1/2 or TEXTURES). "
			"Do you wish to create or import a texture definition list?",
			"No Texture Definitions Found",
			wxYES_NO);

		if (dlg.ShowModal() == wxID_YES)
		{
			CreateTextureXDialog ctxd(nullptr);

			while (true)
			{
				// Check if cancelled
				if (ctxd.ShowModal() == wxID_CANCEL)
					return false;

				if (ctxd.createNewSelected())
				{
					// User selected to create a new TEXTUREx list
					ArchiveEntry* texturex = nullptr;

					// Doom or Strife TEXTUREx
					if (ctxd.getSelectedFormat() == Format::Normal || ctxd.getSelectedFormat() == Format::Strife11)
					{
						// Create texture list
						TextureXList txlist;
						txlist.setFormat(ctxd.getSelectedFormat());

						// Create patch table
						PatchTable ptt;

						// Create dummy patch
						auto dpatch = App::archiveManager().programResourceArchive()->entryAtPath("s3dummy.lmp");
						archive->addEntry(dpatch, "patches", true);
						ptt.addPatch("S3DUMMY");

						// Create dummy texture
						auto dummytex = std::make_unique<CTexture>();
						dummytex->setName("S3DUMMY");
						dummytex->addPatch("S3DUMMY", 0, 0);
						dummytex->setWidth(128);
						dummytex->setHeight(128);
						dummytex->setScale({ 0., 0. });

						// Add dummy texture to list
						// (this serves two purposes - supplies the special 'invalid' texture by default,
						//   and allows the texturex format to be detected)
						txlist.addTexture(std::move(dummytex));

						// Add empty PNAMES entry to archive
						entry_pnames = archive->addNewEntry("PNAMES");
						ptt.writePNAMES(entry_pnames);
						entry_pnames->setType(EntryType::fromId("pnames"));
						entry_pnames->setExtensionByType();

						// Add empty TEXTURE1 entry to archive
						texturex = archive->addNewEntry("TEXTURE1");
						txlist.writeTEXTUREXData(texturex, ptt);
						texturex->setType(EntryType::fromId("texturex"));
						texturex->setExtensionByType();
					}
					else if (ctxd.getSelectedFormat() == Format::Textures)
					{
						// Create texture list
						TextureXList txlist;
						txlist.setFormat(Format::Textures);

						// Add empty TEXTURES entry to archive
						texturex = archive->addNewEntry("TEXTURES");
						texturex->setType(EntryType::fromId("zdtextures"));
						texturex->setExtensionByType();

						return false;
					}

					if (!texturex)
						return false;
				}
				else
				{
					// User selected to import texture definitions from the base resource archive
					auto bra = App::archiveManager().baseResourceArchive();

					if (!bra)
					{
						wxMessageBox(
							"No Base Resource Archive is opened, please select/open one", "Error", wxICON_ERROR);
						continue;
					}

					// Find all relevant entries in the base resource archive
					Archive::SearchOptions opt;
					opt.match_type     = EntryType::fromId("texturex");
					auto import_tx     = bra->findAll(opt); // Find all TEXTUREx entries
					opt.match_type     = EntryType::fromId("pnames");
					auto import_pnames = bra->findLast(opt); // Find last PNAMES entry

					// Check enough entries exist
					if (import_tx.empty() || !import_pnames)
					{
						wxMessageBox(
							"The selected Base Resource Archive does not contain "
							"sufficient texture definition entries",
							"Error",
							wxICON_ERROR);
						continue;
					}

					// Copy TEXTUREx entries over to current archive
					for (auto& a : import_tx)
					{
						auto texturex = archive->addEntry(a, "global", true);
						texturex->setType(EntryType::fromId("texturex"));
						texturex->setExtensionByType();
					}

					// Copy PNAMES entry over to current archive
					entry_pnames = archive->addEntry(import_pnames, "global", true);
					entry_pnames->setType(EntryType::fromId("pnames"));
					entry_pnames->setExtensionByType();
				}

				break;
			}

			return true;
		}

		// 'No' clicked
		return false;
	}
	else // TEXTUREx entry exists
	{
		// TODO: Probably a better idea here to get the user to select an archive to import the patch table from
		// If no PNAMES entry was found, search resource archives
		if (!entry_pnames)
		{
			Archive::SearchOptions opt;
			opt.match_type = EntryType::fromId("pnames");
			entry_pnames   = App::archiveManager().findResourceEntry(opt, archive);
		}

		// If no PNAMES entry is found at all, show an error and abort
		// TODO: ask user to select appropriate base resource archive
		if (!entry_pnames)
		{
			wxMessageBox("PNAMES entry not found!", wxMessageBoxCaptionStr, wxICON_ERROR);
			return false;
		}

		return true;
	}

	return false;
}
Example #11
0
// -----------------------------------------------------------------------------
// Reads in a doom-format TEXTUREx entry.
// Returns true on success, false otherwise
// -----------------------------------------------------------------------------
bool TextureXList::readTEXTUREXData(ArchiveEntry* texturex, const PatchTable& patch_table, bool add)
{
	// Check entries were actually given
	if (!texturex)
		return false;

	// Clear current textures if needed
	if (!add)
		clear();

	// Update palette
	MainEditor::setGlobalPaletteFromArchive(texturex->parent());

	// Read TEXTUREx

	// Read header
	texturex->seek(0, SEEK_SET);

	// Number of textures
	int32_t n_tex = 0;
	if (!texturex->read(&n_tex, 4))
	{
		Log::error("TEXTUREx entry is corrupt (can't read texture count)");
		return false;
	}
	n_tex = wxINT32_SWAP_ON_BE(n_tex);

	// If it's an empty TEXTUREx entry, stop here
	if (n_tex == 0)
		return true;

	// Texture definition offsets
	vector<int32_t> offsets(n_tex);
	if (!texturex->read(offsets.data(), n_tex * 4))
	{
		Log::error("TEXTUREx entry is corrupt (can't read first offset)");
		return false;
	}

	// Read the first texture definition to try to identify the format
	if (!texturex->seek(wxINT32_SWAP_ON_BE(offsets[0]), SEEK_SET))
	{
		Log::error("TEXTUREx entry is corrupt (can't read first definition)");
		return false;
	}
	// Look at the name field. Is it present or not?
	char tempname[8];
	if (!texturex->read(&tempname, 8))
	{
		Log::error("TEXTUREx entry is corrupt (can't read first name)");
		return false;
	}
	// Let's pretend it is and see what happens.
	txformat_ = Format::Normal;

	// Only the characters A-Z (uppercase), 0-9, and [ ] - _ should be used in texture names.
	for (uint8_t a = 0; a < 8; ++a)
	{
		if (a > 0 && tempname[a] == 0)
			// We found a null-terminator for the string, so we can assume it's okay.
			break;
		if (tempname[a] >= 'a' && tempname[a] <= 'z')
		{
			txformat_ = Format::Jaguar;
			// Log::info(1, "Jaguar texture");
			break;
		}
		else if (!((tempname[a] >= 'A' && tempname[a] <= '[') || (tempname[a] >= '0' && tempname[a] <= '9')
				   || tempname[a] == ']' || tempname[a] == '-' || tempname[a] == '_'))
		// We're out of character range, so this is probably not a texture name.
		{
			txformat_ = Format::Nameless;
			// Log::info(1, "Nameless texture");
			break;
		}
	}

	// Now let's see if it is the abridged Strife format or not.
	if (txformat_ == Format::Normal)
	{
		// No need to test this again since it was already tested before.
		texturex->seek(offsets[0], SEEK_SET);
		FullTexDef temp;
		if (!texturex->read(&temp, 22))
		{
			Log::error("TEXTUREx entry is corrupt (can't test definition)");
			return false;
		}
		// Test condition adapted from ZDoom; apparently the first two bytes of columndir
		// may be set to garbage values by some editors and are therefore unreliable.
		if (wxINT16_SWAP_ON_BE(temp.patchcount <= 0) || (temp.columndir[1] != 0))
			txformat_ = Format::Strife11;
	}

	// Read all texture definitions
	for (int32_t a = 0; a < n_tex; a++)
	{
		// Skip to texture definition
		if (!texturex->seek(offsets[a], SEEK_SET))
		{
			Log::error("TEXTUREx entry is corrupt (can't find definition)");
			return false;
		}

		// Read definition
		TexDef tdef;
		if (txformat_ == Format::Nameless)
		{
			NamelessTexDef nameless;
			// Auto-naming mechanism taken from DeuTex
			if (a > 99999)
			{
				Log::error("More than 100000 nameless textures");
				return false;
			}
			char temp[9] = "";
			sprintf(temp, "TEX%05d", a);
			memcpy(tdef.name, temp, 8);

			// Read texture info
			if (!texturex->read(&nameless, 8))
			{
				Log::error("TEXTUREx entry is corrupt (can't read nameless definition #{})", a);
				return false;
			}

			// Copy data to permanent structure
			tdef.flags    = nameless.flags;
			tdef.scale[0] = nameless.scale[0];
			tdef.scale[1] = nameless.scale[1];
			tdef.width    = nameless.width;
			tdef.height   = nameless.height;
		}
		else if (!texturex->read(&tdef, 16))
		{
			Log::error("TEXTUREx entry is corrupt, (can't read texture definition #{})", a);
			return false;
		}

		// Skip unused
		if (txformat_ != Format::Strife11)
		{
			if (!texturex->seek(4, SEEK_CUR))
			{
				Log::error("TEXTUREx entry is corrupt (can't skip dummy data past #{})", a);
				return false;
			}
		}

		// Create texture
		tdef.cleanupName();
		auto tex      = std::make_unique<CTexture>();
		tex->name_    = StrUtil::viewFromChars(tdef.name, 8);
		tex->size_.x  = wxINT16_SWAP_ON_BE(tdef.width);
		tex->size_.y  = wxINT16_SWAP_ON_BE(tdef.height);
		tex->scale_.x = tdef.scale[0] / 8.0;
		tex->scale_.y = tdef.scale[1] / 8.0;

		// Set flags
		if (tdef.flags & Flags::WorldPanning)
			tex->world_panning_ = true;

		// Read patches
		int16_t n_patches = 0;
		if (!texturex->read(&n_patches, 2))
		{
			Log::error("TEXTUREx entry is corrupt (can't read patchcount #{})", a);
			return false;
		}

		// Log::info(1, "Texture #{}: {} patch%s", a, n_patches, n_patches == 1 ? "" : "es");

		for (uint16_t p = 0; p < n_patches; p++)
		{
			// Read patch definition
			Patch pdef;
			if (!texturex->read(&pdef, 6))
			{
				Log::error("TEXTUREx entry is corrupt (can't read patch definition #{}:{})", a, p);
				Log::error("Lump size {}, offset {}", texturex->size(), texturex->currentPos());
				return false;
			}

			// Skip unused
			if (txformat_ != Format::Strife11)
			{
				if (!texturex->seek(4, SEEK_CUR))
				{
					Log::error("TEXTUREx entry is corrupt (can't skip dummy data past #{}:{})", a, p);
					return false;
				}
			}


			// Add it to the texture
			std::string patch;
			if (txformat_ == Format::Jaguar)
			{
				patch = StrUtil::upper(tex->name_);
			}
			else
			{
				patch = patch_table.patchName(pdef.patch);
			}
			if (patch.empty())
			{
				// Log::info(1, "Warning: Texture %s contains patch %d which is invalid - may be incorrect PNAMES
				// entry", tex->getName(), pdef.patch);
				patch = fmt::format("INVPATCH{:04d}", pdef.patch);
			}

			tex->addPatch(patch, pdef.left, pdef.top);
		}

		// Add texture to list
		addTexture(std::move(tex));
	}

	return true;
}