How can i convert FBX embedded texture to TArray<uint8> Data? - unreal-engine4

I want to make a function that returns the textures built into FBX as 'TArray[uint8]' or UTexture2D using Assimp library. This is my code.
void UAIScene::GetTexture2D(bool& IsValid, UTexture2D*& ReturnedTexture)
{
IsValid = false;
UTexture2D* LoadedT2D = NULL;
TArray<uint8> RawFileData;
IImageWrapperModule& ImageWrapperModule = FModuleManager::LoadModuleChecked<IImageWrapperModule>(FName("ImageWrapper"));
aiString texture_file;
scene->mMaterials[0]->Get(AI_MATKEY_TEXTURE(aiTextureType_DIFFUSE, 0), texture_file);
if (const aiTexture* texture = scene->GetEmbeddedTexture(texture_file.C_Str())) {
//Here Is Problem
RawFileData = *(TArray<uint8>*) & (texture->pcData[0]);
TSharedPtr<IImageWrapper> ImageWrapper = ImageWrapperModule.CreateImageWrapper(ImageWrapperModule.DetectImageFormat(RawFileData.GetData(), RawFileData.Num()));
if (ImageWrapper.IsValid() && ImageWrapper->SetCompressed(RawFileData.GetData(), RawFileData.Num()))
{
TArray<uint8> UncompressedBRGA;
if (ImageWrapper->GetRaw(ERGBFormat::BGRA, (int32)8, UncompressedBRGA))
{
LoadedT2D = UTexture2D::CreateTransient(ImageWrapper->GetWidth(), ImageWrapper->GetHeight(), PF_B8G8R8A8);
if (!LoadedT2D)
{
IsValid = false;
}
void* TextureData = LoadedT2D->PlatformData->Mips[0].BulkData.Lock(LOCK_READ_WRITE);
FMemory::Memcpy(TextureData, UncompressedBRGA.GetData(), UncompressedBRGA.Num());
LoadedT2D->PlatformData->Mips[0].BulkData.Unlock();
LoadedT2D->UpdateResource();
}
}
ReturnedTexture = LoadedT2D;
IsValid = true;
}
else {
}
}
But Assimp's raw image file doesn't cast to TArray. Where do I have to fix to change Assimp's aiTexel to TArray?
This comment is my attempt.
//TextureBinary = *Cast<TArray<uint8>>(texture->pcData);

If I get the documentation for TArray right you need to copy the data with memcpy. You need the starting address of the embedded texture, the start-pointer of the TArray instance by GetData() or something similar and the size for the embedded texture which shall get copyied:
memcpy(RawFileData.GetData(), static_cast<void*>(&LoadedT2D), texSize);
Just make sure that the buffer-size for the TArray instance is big enough. Hope that helps.

Related

ESP32-CAM buffer

When I initialize the camera I use this:
#include "esp_camera.h"
bool initCamera(){
Serial.print("Iniciando Cámara ...");
camera_config_t config;
config.ledc_channel = LEDC_CHANNEL_0;
config.ledc_timer = LEDC_TIMER_0;
config.pin_d0 = Y2_GPIO_NUM;
...
...
config.xclk_freq_hz = 20000000;
config.pixel_format = PIXFORMAT_JPEG;
config.frame_size = FRAMESIZE_XGA;
config.jpeg_quality = 8;
config.fb_count = 1;
config.grab_mode = CAMERA_GRAB_LATEST; <<<<<<<
// camera init
esp_err_t err = esp_camera_init(&config);
if (err != ESP_OK){
Serial.printf("... error 0x%x", err);
return false;
}
sensor_t *s = esp_camera_sensor_get();
Serial.println("... OK");
CAMARA_OK = true;
return true;
}
But when I ask for a capture:
static esp_err_t capture_handler(httpd_req_t *req){
cambiosConfiguracion(req);
camera_fb_t *fb = NULL;
esp_err_t res = ESP_OK;
fb = esp_camera_fb_get();
if (!fb){
Serial.println("Camera capture failed");
httpd_resp_send_500(req);
return ESP_FAIL;
}
...
the image it shows me is from before, it takes a delayed capture.
I want that when I ask for a capture, it gives me the one from that moment, not the one stored in the buffer
I have the same problem, I've been looking for the solution for days and although it seems to be fine, it doesn't do what it's supposed to do.
At the moment I am using this "trick":
fb = esp_camera_fb_get();
esp_camera_fb_return(fb);
fb = esp_camera_fb_get();
I ask for a capture, I discard it and then I ask for another one, which is current

unity custom editor with arrays

I'm in the process of creating a game and the scripts are getting pretty big. For more clarity I want to work with the custom editor. But I have problems with types like classes, gameobjects and especially arrays.
As you can hopefully see in my picture, it is very easy to make basic types like string and float etc visible. But how does it work with an array ? and especially if the array is still a class or a rigidbody or a gameobject ? I need if possible a good explanation or direct solution. I would be very grateful for your help
enter image description here
Note: If your just looking to beautify/improve your inspector, rather than doing it as an actual project/experience, your better off looking for plugins.
The Custom-Editor API that Unity provides are a bunch of Tools, not a House. You will end up pouring a lot of effort into making your inspector 'look neater'.
If you just want to create a game, use plugins to decorate your inspector.
MyBox is one of the Plugins I use, and recommend.
Now back to the question
I managed to pull it off by using a combination of EditorGUILayout.Foldout and looping through the array size to create multiple EditorGUILayout.IntField.
// True if the user 'opened' up the array on inspector.
private bool countIntsOpened;
public override void OnInspectorGUI() {
var myTarget = (N_USE)target;
myTarget.myTest.name = EditorGUILayout.TextField("see name", myTarget.myTest.name);
myTarget.myTest.countOnly = EditorGUILayout.FloatField("see float", myTarget.myTest.countOnly);
// Create int array field
myTarget.myTest.countInts = IntArrayField("see int[]", ref countIntsOpened, myTarget.myTest.countInts);
}
public int[] IntArrayField(string label, ref bool open, int[] array) {
// Create a foldout
open = EditorGUILayout.Foldout(open, label);
int newSize = array.Length;
// Show values if foldout was opened.
if (open) {
// Int-field to set array size
newSize = EditorGUILayout.IntField("Size", newSize);
newSize = newSize < 0 ? 0 : newSize;
// Creates a spacing between the input for array-size, and the array values.
EditorGUILayout.Space();
// Resize if user input a new array length
if (newSize != array.Length) {
array = ResizeArray(array, newSize);
}
// Make multiple int-fields based on the length given
for (var i = 0; i < newSize; ++i) {
array[i] = EditorGUILayout.IntField($"Value-{i}", array[i]);
}
}
return array;
}
private static T[] ResizeArray<T>(T[] array, int size) {
T[] newArray = new T[size];
for (var i = 0; i < size; i++) {
if (i < array.Length) {
newArray[i] = array[i];
}
}
return newArray;
}
Not as nice or neat as Unity's default. But gets the job done.
P.S: You can copy-paste your code when asking questions, rather than posting it as an image. It helps a lot.

Setting material in Unity in run time issue

When I change material in runtime with this it does not work
expoSceneLarge.GetComponent<Renderer>().materials[0] = availableMaterials[selectedMaterialIndex];
however using this
expoSceneLarge.GetComponent<Renderer>().material = availableMaterials[selectedMaterialIndex];
material is being changed in run time.
What confuses me is that material, according to Unity return the first element in materials attached to renderer, so why materials[0] does not work?
Found a solution.
I has to create new array of materials, change the once I was interested in and the assign whole array to mesh renderer. Here is a a full code for future reference.
var newMaterials = new Material[_expoMaterials.Count()];
for(int i = 0; i < newMaterials.Count(); i++)
{
// i = 1 for floor
if(i == 1)
{
newMaterials[i] = availableMaterials[selectedMaterialIndex];
}
else
{
newMaterials[i] = _expoMaterials[i];
}
}
expoSceneLarge.GetComponent<MeshRenderer>().materials = newMaterials;

How add code to display both Character avatar and text in 2 different scenes?

I am making a scene game with a Character Avatar and its name (The interface has a text field to add in it its name) and then when I clicked the DONE button, I want to run a new scene to display both Character Avatar and the name added into text field, for it, Could anybody help me to make the code to do it? Thanks in advance Alejandro Castan Ps. Sorry for my little English and hope you can understand me
void FinishWindowContents (int windowID) {
GUILayout.BeginHorizontal(horizontalLayoutStyle);
GUILayout.BeginVertical(verticalLayoutStyle);
GUILayout.Label ("Name", bottomBarLabelStyle);
characterName = GUILayout.TextField(characterName);
GUILayout.EndVertical();
GUILayout.BeginVertical(verticalLayoutStyle);
if (characterName.Length == 0) {
GUI.enabled = false;
}
if (GUILayout.Button("Done", bottomBarButtonStyle)) {
// Save the character, fade out the camera and load up the game scene
GameObject avatarGO;
if (selectedGender == "Man") {
avatarGO = maleAvatarSpawn;
} else {
avatarGO = femaleAvatarSpawn;
}
var avatar = avatarGO.GetComponent<UMAAvatarBase>();
if( avatar != null )
{
string finalPath = savePath + "/" + characterName + ".txt";
if (finalPath.Length != 0)
{
PersistentNameHolder.characterName = characterName;
var asset = ScriptableObject.CreateInstance<UMATextRecipe>();
asset.Save(avatar.umaData.umaRecipe, avatar.context);
System.IO.File.WriteAllText(finalPath, asset.recipeString);
ScriptableObject.Destroy(asset);
// If the camera has a fader, make it fade out and load the game scene, otherwise just load the scene ourselves
if (orbitCamera.GetComponent<CameraFader>() != null) {
orbitCamera.GetComponent<CameraFader>().fadeOutAndLoadScene(gameSceneName);
} else {
Application.LoadLevel(gameSceneName);
}
}
}
}
if (characterName.Length == 0) {
GUI.enabled = true;
}
GUILayout.EndVertical();
GUILayout.EndVertical();
}
Note-I added some code(this code is more complex that I asked above) you can see it. This code is from Unity plugin and what I would need to add only the text added in the text field into the new scene when I do click in the Done button.
PlayerPrefs is a way to save data between scenes.
It doesn't need some extra code and is great for what you are doing because it allows you to write/read in any moment of your game.
Hope you'll find useful.

Touches on transparent PNGs

I have a PNG in a UIImageView with alpha around the edges (let's say a circle). When I tap it, I want it to register as a tap for the circle if I'm touching the opaque bit, but a tap for the view behind if I touch the transparent bit.
(BTW: On another forum, someone said PNGs automatically do this, and a transparent PNG should pass the click on to the view below, but I've tested it and it doesn't, at least not in my case.)
Is there a flag I just haven't flipped, or do I need to create some kind of formula: "if tapped { get location; calculate distance from centre; if < r { touched circle } else { pass it on } }"?
-k.
I don't believe that PNGs automatically do this, but can't find any references that definitively say one way or the other.
Your radius calculation is probably simpler, but you could also manually check the alpha value of the touched pixel in your image to determine whether to count it as a hit. This code is targetted at OS X 10.5+, but with some minor modifications it should run on iPhone: Getting the pixel data from a CGImage object. Here is some related discussion on retrieving data from a UIImage: Getting data from an UIImage.
I figured it out...the PNG, bounding box transparency issue and being able to click through to another image behind:
var hitTestPoint1:Boolean = false;
var myHitTest1:Boolean = false;
var objects:Array;
clip.addEventListener(MouseEvent.MOUSE_DOWN, doHitTest);
clip.addEventListener(MouseEvent.MOUSE_UP, stopDragging);
clip.buttonMode = true;
clip.mouseEnabled = true;
clip.mouseChildren = true;
clip2.addEventListener(MouseEvent.MOUSE_DOWN, doHitTest);
clip2.addEventListener(MouseEvent.MOUSE_UP, stopDragging);
clip2.buttonMode = true;
clip2.mouseEnabled = true;
clip2.mouseChildren = true;
clip.rotation = 60;
function doHitTest(event:MouseEvent):void
{
objects = stage.getObjectsUnderPoint(new Point(event.stageX, event.stageY));
trace("Which one: " + event.target.name);
trace("What's under point: " + objects);
for(var i:int=0; i
function stopDragging(event:MouseEvent):void
{
event.target.stopDrag();
}
function realHitTest(object:DisplayObject, point:Point):Boolean
{
/* If we're already dealing with a BitmapData object then we just use the hitTest
* method of that BitmapData.
*/
if(object is BitmapData)
{
return (object as BitmapData).hitTest(new Point(0,0), 0, object.globalToLocal(point));
}
else {
/* First we check if the hitTestPoint method returns false. If it does, that
* means that we definitely do not have a hit, so we return false. But if this
* returns true, we still don't know 100% that we have a hit because it might
* be a transparent part of the image.
*/
if(!object.hitTestPoint(point.x, point.y, true))
{
return false;
}
else {
/* So now we make a new BitmapData object and draw the pixels of our object
* in there. Then we use the hitTest method of that BitmapData object to
* really find out of we have a hit or not.
*/
var bmapData:BitmapData = new BitmapData(object.width, object.height, true, 0x00000000);
bmapData.draw(object, new Matrix());
var returnVal:Boolean = bmapData.hitTest(new Point(0,0), 0, object.globalToLocal(point));
bmapData.dispose();
return returnVal;
}
}
}