Stratos: Punto de Encuentro de Desarrolladores

¡Bienvenido a Stratos!

Acceder

Foros





Pregunta Técnica Sobre C#

Iniciado por , 24 de Febrero de 2005, 01:13:12 PM

« anterior - próximo »

 Bien, mi pregunta es la siguiente, estoy haciendo un cargador de ficheros bsp de quake3 usando como base el motor Hadd, pero cargo casi todo pero cuando llego a cargar los lightmap que están en una zona del fichero bsp, no lo hago correctamante, me podrías ayudar?

Os explico brevemente como se hace en c++ para ver como se haría en c#

se emplea esta estructura:

struct tBSPLightmap
{
   byte mapaDeBits[128][128][3]; // Datos RGB en una imagen de 128x128  
};


   // Buscamos las estructuras de los lightmaps en el archivo
   fseek(fp, bloques[kLightmaps].desplaz, SEEK_SET);

   // Los recooremos todos y los leemos
   for(i = 0; i < m_iNumDeLightmaps; i++)
   {
      // Leemos los valores rgb para cada lightmap
      fread(&lightmap, 1, sizeof(tBSPLightmap), fp);

      // Creamos un lightmap de 128x128 por cada estrucutura q haya
      CrearTexturaLightmap(i,lightmap.mapaDeBits, 128, 128);
   }


Bien, yo logro cargar los lightmaps pero no los logro pasar correctamente a un jagged array del tipo [128][128][3]

A ver si os animais y me ayudais.

Gracias de antemano.

Haddd

 Mírate en la ayuda BinaryReader


BeRSeRKeR

 Yo utilizaba un array unidimensional de bytes. Aunque realmente ese array sólo lo utilizaba en tiempo de carga ya que lo que se mantenía era un array de texturas de Direct3D.

Así, para acceder a los pixels del lightmap en el array de bytes hacía:

for (i = 0; i < m_iNumLightMaps; i++)
{
   for (j = 0; j < 128 * 128; j++)
   {
       float r = (float)lightmaps[i * LIGHTMAP_BLOCK + (j * 3 + 0)];
       float g = (float)lightmaps[i * LIGHTMAP_BLOCK + (j * 3 + 1)];
       float b = (float)lightmaps[i * LIGHTMAP_BLOCK + (j * 3 + 2)];
   }
}


Como los lightmaps de quake3 eran de 128x128 y 24 bits por pixel, LIGHTMAP_BLOCK es:

#define LIGHTMAP_BLOCK    (128 * 128 * 3)

De todas formas sí es cierto que también deberías poderlo hacer con ese tipo de arrays. ¿El resto de datos del BSP sí los puedes leer bien?.

Saludos.
¡Si te buscan en nombre de la ley, huye en nombre de la libertad!!

zupervaca

 buenas, he visto este codigo y no es que este mal, pero podria optimizarse y realizar menos operaciones matematicas, no te lo tomes a mal ber  ;)

for (i = 0; i < m_iNumLightMaps; i++)
{
  for (j = 0; j < 128 * 128; j++)
  {
      float r = (float)lightmaps[i * LIGHTMAP_BLOCK + (j * 3 + 0)];
      float g = (float)lightmaps[i * LIGHTMAP_BLOCK + (j * 3 + 1)];
      float b = (float)lightmaps[i * LIGHTMAP_BLOCK + (j * 3 + 2)];
  }
}

mejor seria asi

z = 0;
for (i = 0; i < m_iNumLightMaps; i++)
{
  for (j = 0; j < 128 * 128; j++)
  {
      float r = (float)lightmaps[z]; z++;
      float g = (float)lightmaps[z]; z++;
      float b = (float)lightmaps[z]; z++;
  }
}

no se si el c# puedes manejar punteros ya que si es asi se podria optimizar muchos mas ahorrandos resolver la direccion numerica del array haciendolo directamente con el puntero

sobre el tema del post, mira ver si el problema lo tienes en las segundas coordenadas de texturas y no al leer los lightmaps

saludos a todos

BeRSeRKeR

 No me lo tomo a mal pero como es algo que se realiza en tiempo de carga pues no me preocupé de hacerlo con punteros (esa parte es de un motor que hicimos ProD y yo hace mucho tiempo).

Saludos.
¡Si te buscan en nombre de la ley, huye en nombre de la libertad!!

 Bien como veo que hay nivel, entonces vayamos al meollo, el problema no es que no lo lea, sino que al aplicarlo a una textura me falla, lo he pasado a una textura normal, para ver si obtenía bien la imagen y ahí es donde me doy cuenta que no lo hago correctamente, voy a pasar a poner todo mi código y a ver si alguien me puede ayudar a encontrar mi fallo, ok?

'Declaración del struct
public struct tBSPLightmap
{
  public byte[] mapaDeBits; //(128 * 128 * 3) Datos RGB en una imagen de 128x128
}


           // Buscamos las estructuras de las texturas light map en el archivo
           if (m_iNumDeLightmaps>0)
           {
               //Si hay texturas se lightmaps las creo.
               m_pLightmap = new Texture[m_iNumDeLightmaps];
           }
           //Ahora procedo a leerlas del fichero.
           fs.Seek((long)bloques[(int)eBloquess.kLightmaps].desplaz, SeekOrigin.Begin); //Me posiciono dentro del archivo.
           for (int i = 0; i < m_iNumDeLightmaps; i++)
           {
               //Leo los valores de mi light maps.                
               lightmap.mapaDeBits = r.ReadBytes(128*128*3);                
               
               // Creamos un lightmap de 128x128 por cada estrucutura q haya
               CrearTexturaLightmap(i, lightmap.mapaDeBits, 128, 128);
           }


Y ahora os escribo la función CrearTexturaLightmap:


       public void CrearTexturaLightmap(int indice, byte[] pMapaDeBits, int ancho, int alto)
       {
           CambiarGamma(pMapaDeBits, ancho, alto, 9f); //Aquí se podrá usar una variable global para cambiar la gamma de todas las texturas de light map.
           m_pLightmap[indice] = new Texture(device, ancho, alto, 1, Usage.None, Format.A8R8G8B8, Pool.Managed);
           int[] buffer = new int[ancho * alto];
           GraphicsStream gs = null;
           gs = m_pLightmap[indice].LockRectangle(0, LockFlags.None);


           for (int x = 0; x < ancho; x++)
           {
               int offset = x * ancho;
               for (int y = 0; y < alto; y++)
               {
                   byte r = pMapaDeBits[offset + y * 3 + 0];
                   byte g = pMapaDeBits[offset + y * 3 + 1];
                   byte b = pMapaDeBits[offset + y * 3 + 2];
                   byte a = 255;
                   buffer[offset + y] = (a << 24 | r << 16 | g << 8 | B);
               }
           }

           gs.Write(buffer);
           m_pLightmap[indice].UnlockRectangle(0);
       }


Aclaración, CambiarGamma sólo hace eso, no tiene nada especial.

Sobre el formato de las imágines ya se que son R5G6B5, pero eso es igual, pues yo la cambio en tiempo real al formato A8R8G8B8, decir, que si uso el formato origal tb falla.

Es decir, el fallo es que la imagen que obtengo no es la correcta.

Y bueno, decir tb que efectivamente la logré cargar en un jagged array de [128][128][3], leyendo byte a byte del fichero binario, pero como me fallaba igual, pues lo cambie por este otro sistema, en definitiva de ambas formas me carga la textura mal, es como si al leer los bytes y ponerlos en la imagen resultante no lo hicise en su sitio.

A ver si alguien me hecha un cable, que la verdad es que me tiene ese detalle muy atrancado.

Gracias de antemano.

 Me estoy imaginando una cosa y ese será el problema.

Esas texturas de 128 x 128 cada una de ellas lleva varias imágenes de lightmap distribuidas o deben de llevar una sólo, es que es posible que me funcione correctamente y al visionarla me crea que no.


 Y ya puestos a preguntar quizás lo que no haga correctamente sea al cargar el estado de mi dispositivo para pintar texturas y texturas de lightmap. Este sería mi uso.

           // Especificamos los estados de render y texture-stages que necesitamos
           device.RenderState.AlphaBlendEnable = false;
           device.RenderState.AlphaSourceBlend = Blend.SourceAlpha;
           device.RenderState.DestinationBlend = Blend.One;
           device.RenderState.AlphaTestEnable = false;
           
           device.RenderState.FillMode = FillMode.Solid;
           device.RenderState.CullMode = Cull.CounterClockwise;
           device.RenderState.Lighting = false;
           
           device.RenderState.ZBufferEnable = true;
           device.RenderState.StencilEnable = true;
           device.RenderState.Clipping = true;
           device.ClipPlanes.DisableAll();
           device.RenderState.VertexBlend = VertexBlend.Disable;
           device.RenderState.IndexedVertexBlendEnable = false;
           device.RenderState.FogEnable = false;

           device.TextureState[0].ColorOperation = TextureOperation.SelectArg1;
           device.TextureState[0].ColorArgument1 = TextureArgument.TextureColor;
           device.TextureState[0].ColorArgument2 = TextureArgument.Diffuse;
           device.TextureState[0].AlphaArgument1 = TextureArgument.TextureColor;
           device.TextureState[0].AlphaArgument2 = TextureArgument.Diffuse;
           device.TextureState[0].AlphaOperation = TextureOperation.Disable;
           device.TextureState[0].TextureCoordinateIndex = (int)TextureCoordinateIndex.PassThru;
           device.TextureState[0].TextureTransform = TextureTransform.Disable;
           
           device.TextureState[1].ColorOperation = TextureOperation.Modulate;
           device.TextureState[1].TextureCoordinateIndex = (int)TextureCoordinateIndex.PassThru;
           device.TextureState[1].AlphaOperation = TextureOperation.Disable;
           device.TextureState[1].ColorArgument1 = TextureArgument.TextureColor;
           device.TextureState[1].ColorArgument2 = TextureArgument.Current;

           device.SamplerState[0].MinFilter = TextureFilter.Linear;
           device.SamplerState[0].MagFilter = TextureFilter.Linear;
           device.SamplerState[0].MipFilter = TextureFilter.Linear;
           device.SamplerState[1].MinFilter = TextureFilter.Linear;
           device.SamplerState[1].MagFilter = TextureFilter.Linear;
           device.SamplerState[1].MipFilter = TextureFilter.Linear;

           device.SamplerState[0].AddressU = TextureAddress.Wrap;
           device.SamplerState[0].AddressV = TextureAddress.Wrap;

Es posible que no lo haga correctamente?

zupervaca

 comprueba que al incrementar el rojo, verde o azul en la correccion del gama no te pases de 255 ya que si se pasa da "la vuelta", el factor de la gama te recomiendo ponerla en 3 o 4 para que se acerque al de kake3  ;)


ej: si rojo > 255 entons rojo = 255

saludos

BeRSeRKeR

 En cada uno de esos sets de lightmaps de 128x128 hay muchos lightmaps empaquetados.
¡Si te buscan en nombre de la ley, huye en nombre de la libertad!!

masaniz

 Gracias berseker entonces los lightmaps los cargo bien.

Y zuperbaca el código que uso para cambiar la gamma es el siguiente:
       public void CambiarGamma(byte[] pImagen, int ancho, int alto, float factor)
       {
           for (int x = 0; x < ancho; x++)
           {
               for (int y = 0; y < alto; y++)
               {

                   float scale = 1.0f, temp = 0.0f;
                   float r = 0, g = 0, b = 0;

                   r = (float)pImagen[x + y + 0];
                   g = (float)pImagen[x + y + 1];
                   b = (float)pImagen[x + y + 2];

                   r = r * factor / 255.0f;
                   g = g * factor / 255.0f;
                   b = b * factor / 255.0f;

                   if (r > 1.0f && (temp = (1.0f / r)) < scale) scale = temp;
                   if (g > 1.0f && (temp = (1.0f / g)) < scale) scale = temp;
                   if (b > 1.0f && (temp = (1.0f / B)) < scale) scale = temp;

                   scale *= 255.0f;
                   r *= scale; g *= scale; b *= scale;

                   pImagen[x + y + 0] = (byte)r;
                   pImagen[x + y + 1] = (byte)g;
                   pImagen[x + y + 2] = (byte)b;
               }
           }
       }


Y sobre los estados estoy un poco liado sobre todo por este parámetro:

device.TextureState[1].TextureCoordinateIndex = (int)TextureCoordinateIndex.PassThru;

Si pongo eso hace cosas raras, alguien me dijo que usase esto otro
device.TextureState[1].TextureCoordinateIndex = 1
así sale bien, pero los colores no me gustan, o sale verdoso, azulado, no se, me hace cosas raras.

masaniz

 Disculparme por mi ignoración, pero la función CambiarGamma no la cambie del tutorial que estoy siguiente de c++ y trasapasando a c# (pa aprender un poquillo :-)) y ahora la he cambiado por esta otra que he elaborado, pues fallaba ahí:

       public void CambiarGamma(byte[] pImagen, int ancho, int alto, float factor)
       {
           for (int x = 0; x < ancho*alto*3; x+=3)
           {
               float scale = 1.0f, temp = 0.0f;
               float r = 0, g = 0, b = 0;

               r = (float)pImagen[x + 0];
               g = (float)pImagen[x + 1];
               b = (float)pImagen[x + 2];

               r = r * factor / 255.0f;
               g = g * factor / 255.0f;
               b = b * factor / 255.0f;

               if (r > 1.0f && (temp = (1.0f / r)) < scale) scale = temp;
               if (g > 1.0f && (temp = (1.0f / g)) < scale) scale = temp;
               if (b > 1.0f && (temp = (1.0f / B)) < scale) scale = temp;

               scale *= 255.0f;
               r *= scale; g *= scale; b *= scale;

               pImagen[x + 0] = (byte)r;
               pImagen[x + 1] = (byte)g;
               pImagen[x + 2] = (byte)b;
           }
       }


Pero aún así me gusataría saber bien lo de los estados del dispositivo los valores más correctos en c#.

Gracias de nuevo

Y cuando aprenda un poquito más pues intentaré colaboraros en algo.

ethernet

 Donde esté la aritmética de punteros que se quiten los indexados guarros. Supongo que C# no tiene punteros.. :P

zupervaca

 los estados de texturas los pones bien, basicamente dejas los de directx por defecto, lo unico decirte que desactives el 1 y solo lo actives cuando es necesario ya que aunque indiques que no tiene textura, al dejarlo activado las directx realizaran mas operaciones que si lo desactivaras.

como ultimo consejo te recomiendo que hagas un interface para los cambios de estado del device para no realizar tantas llamadas a los objetos com de directx

BeRSeRKeR

 Me ha entrado el gusanillo así que he hecho un cargador de BSPs del quake3 utilizando el motor C# y he probado a visualizar los lightmaps como textura D3D sobre un polígono y éste es el resultado:



Este es el lightmap en formato "raw" que he visualizado con el Photoshop:



Este es el código utilizado:

private void LoadLightmaps()
{
       file.Seek(header.lumps[Q3LUMP_LIGHTING].offset, SeekOrigin.Begin);

       numLightmaps = header.lumps[Q3LUMP_LIGHTING].len / LIGHTMAP_BLOCK;

       byte[] lightmaps = reader.ReadBytes((int)(LIGHTMAP_BLOCK * numLightmaps));

       // Escribe los lightmaps en formato raw
       for (int i = 0; i < numLightmaps; i++)
       {
               FileStream fOut = new FileStream("lightmap0" + i + ".raw", FileMode.Create);
               int offset = (int)LIGHTMAP_BLOCK * i;
               fOut.Write(lightmaps, offset, (int)LIGHTMAP_BLOCK);
               fOut.Close();
       }

       OutputLightmaps(lightmaps);
}

public void OutputLightmaps(byte[] lightmaps)
{
       lmTextures = new Texture[numLightmaps];

       int pixel = 0;
       for (int i = 0; i < numLightmaps; i++)
       {
               lmTextures[i] = new Texture(Haddd.Video.Device, 128, 128, 1, Usage.None, Format.X8R8G8B8, Pool.Managed);

               int pitch;
               GraphicsStream gs = lmTextures[i].LockRectangle(0, LockFlags.Discard, out pitch);

               for (int j = 0; j < 128 * 128; j++)
               {
                       byte r = lightmaps[pixel++];
                       byte g = lightmaps[pixel++];
                       byte b = lightmaps[pixel++];
                       byte a = 255;

                       gs.WriteByte(b);
                       gs.WriteByte(g);
                       gs.WriteByte(r);
                       gs.WriteByte(a);
               }

               lmTextures[i].UnlockRectangle(0);
       }
}


Fíjate que a la hora de guardar el pixel del lightmap lo hago en el orden BGRA.

Saludos.
¡Si te buscan en nombre de la ley, huye en nombre de la libertad!!






Stratos es un servicio gratuito, cuyos costes se cubren en parte con la publicidad.
Por favor, desactiva el bloqueador de anuncios en esta web para ayudar a que siga adelante.
Muchísimas gracias.