Stratos: Punto de Encuentro de Desarrolladores

¡Bienvenido a Stratos!

Acceder

Foros





Menu

Mostrar Mensajes

Esta sección te permite ver todos los posts escritos por este usuario. Ten en cuenta que sólo puedes ver los posts escritos en zonas a las que tienes acceso en este momento.

Mostrar Mensajes Menu

Mensajes - zupervaca

#1
General Programadores / Programación cruzada con C++
15 de Abril de 2008, 08:42:49 PM
Yo uso otra solucion que es mezcla de varias:

itimer.h
class ITimer
{
public:
  virtual void get() = 0;
};

timer_linux.h
class Timer_Linux : public ITimer
{
  void get(){...};
};

timer_win.h
class Timer_Win : public ITimer
{
  void get(){...};
};

timer_api.h
#ifdef windows
  #include "timer_win.h"
  typedef Timer Timer_win;
#end
#ifdef linux
  #include "timer_linux.h"
  typedef Timer Timer_linux;
#endif

En definitiva ITimer te queda como clase abstracta para crear todas las plataformas que quieras y despues creas una nuevo tipo de dato que sera Timer que es el que maneja el usuario desde el include timer_api.h
Para que queda mas bonito puedes usar namespaces y crear carpetas diferentes, es decir:

system
  time
     api
        win32
           timer.h
        linux
           timer.h
     api.h
     itimer.h
...

Un ejemplo mas claro lo tienes en la libreria multiplataforma y multiapi que he realizado hace unos años.
La mayor ventaja de este sistema es que aunque uses funciones virtuales, estas, son resueltas en tiempo de compilacion ya que solo tendras una clase Timer final.
Otra nota importante antes que se me olvide es que si vas a hacer algo multiplataforma es que llames a todos los archivos que hagas en minusculas, no pongas mayusuclas ya que hay compiladores que no se los tragan, a parte el visual studio a veces te cambie los nombres a minusculas.

Saludos
#2
Off-topic / Busco habitación para compartir en Madrid
08 de Abril de 2008, 08:54:56 PM
Hola,

yo me mudo cada cierto tiempo por el trabajo que tengo, prueba en http://www.idealista.com/pagina/portada, le das a habitacion en vez de alquiler y buscar en la zona que mas cerca del trabajo estes o mejor comunicada.

Saludos
#3
EX3 a lo que me refiero es con cachear calculos es a mas que nada las matrices de transformacion y proyeccion, cada vez que quieras pintar un sprite tendras que indicar las coordenadas de los vertices ya transformadas.

Loover lo de las matrices no lo digo por decir, me baso en pruebas que realice con un sobremesa y dos portatiles diferentes, nunca se debe de dar por sentado algo que leas en una pagina web, lo mejor es comprobarlo por uno mismo.
#4
Hola,

creo que os estais liando con cosas sin importancia:
- Si quereis probar si el zbuffer consume mucho lo teneis facil, simplemente activarlo con los renders que teneis ahora, vereis que no se nota.
- El tamaño del vertexbuffer optimo ronda los 4000 vertices, aunque depende de la declaracion del vertice que se use, lo optimo es quedarse por los 96KB de tamaño, mas de esto puede generar una perdida de velocidad.
- Cuando el numero de sprites a renderizar supere el vertexbuffer lo que teneis que hacer es forzar el render y volver a comenzar.
- No teneis por que usar esta tecnica siempre, es mas, debe depender del programador el agrupar los sprites, es decir, el programador tiene que pintar todos los ovnis, despues todos los misiles, etc. ya que si vais a pintar un sprite unico en pantalla usar esta tecnica es peor que usar directamente un solo DrawPrimitive ya que gastais cpu para nada.
- Se deben de cachear todos los calculos posibles como matrices de transformacion de proyeccion, etc.
- Tener vuestras propias clases de matrices ya que sera mas rapido llamar al codigo de vuestro juego que al api de direct3dx.
- Las animaciones de un mismo sprite deben estar en una unica textura, si es posible meter incluso varias en la misma
- Con los shaders se puede hacer una tecnica un pelin mas avanzada y es pintar hasta 8 texturas diferentes con un solo vertexbuffer, por desgracia esta idea que tuve hace tiempo no he podido probarla aun, ademas tenemos el problema de que no todas las tarjetas graficas soportan shaders 1_1 ni 8 texturas simultaneas.
- Se me olvidaba: Usar DrawPrimitive ya que bloquear y desbloquear un vertexbuffer es mas rapido que crearlo, bloquearlo y desbloquearlo que es como lo hace DrawPrimitiveUP.
- Usar indexbuffer para calcular menos vertices y solo usar 4 por cada sprite.
- El indexbuffer solo se debe de inicializar una vez ya que no variara nunca.
- Dejar el blending activado no baja la velocidad, ademas la mayoria de las veces usaremos el source y dest mismo para pintar con transparencia. (mientras menos pixels se pinten mas rapido va el render)

Despues de dos años no me acuerdo de muchas mas cosas con las que optimizar, ademas ya no estoy en el mundillo de los juegos asi que puede que todo lo que digo este obsoleto, aunque claramente el test de los conejos sigue tirando de una forma brutal :P

Saludos
#5
IndieLib / BenchMark 01: Alien Invasion
30 de Marzo de 2008, 08:45:48 AM
Si quieres un codigo de ejemplo pasate por aqui: http://www.codeplex.com/dibplus/Release/ProjectReleases.aspx?ReleaseId=610
No digo que sea el mejor codigo del mundo, pero como guia te valdra.
La clase que te interesa esta en System/Drawing/sprite.h
Si le pegas un ojo veras que se crea un vertexbuffer e indexbuffer, este ultimo se inicializa una vez (cuando se crea) y el vertexbuffer se le ponen valores mas o menos coherentes (aunque no haria falta).
Para comenzar el render se llama a la funcion Begin y cuando quieres terminarlo a la End, despues entra la llamada a estas dos funciones tienes funciones que te permiten cambiar el estado de los sprites, estas propias funciones se encarga de pintar todo si es necesario, es decir, si cambia algun estado del render.

Saludos y espero que esto te ayude a mejorar la dx_lib32
#6
IndieLib / BenchMark 01: Alien Invasion
29 de Marzo de 2008, 11:06:23 AM
Hola,

Cita de: "Loover"Pues si es raro, pero vamos, no hago nada fuera de lo normal. Un DrawPrimitiveUp por objeto, como dije. Parece ser que cuando hay muchas llamadas a DrawPrimitiveUp seguidas, la aplicación se vuelve más dependiente de la CPU que de la GPU... ¿parece eso, no?
Hace unos años que ya comprobe esto con el test de los conejos de mi pagina web y ahora miles de tutoriales ya lo explican por fin, lo mejor que puedes hacer es que si vas a pintar la misma texturas repetidas veces tengas un vertexbuffer e indexbuffer grande y lo modifiques por con la cpu. (el indexbuffer solo se tendria que modificar una vez, cuando se cree)
El problema al usar una llamada por objeto es que la cpu espera a la confirmacion de la gpu de que lo ha pintado, asi que la cpu se queda parada mientras tanto.
Otro de los problemas es que cada llamada direct3d va a tener que llegarle al driver, cosa mala y que se debe de evitar ya que todas las llamadas de tu juego que salgan del codigo de tu juego seran lentisimas, de hay aquel codigo para el manager de cambios de estados.

Para demostrarte lo que te comento prueba este test de velocidad de los conejos que hice por el año 2006: http://www.davidib.com/projects/rabbits/rabbits.zip

Saludos

PD: El test de los ovnis me da ~53fps
#7
Hola,

esta es la funcion de la libconio para linux

int getch()
{
       struct termios t;
       int c;

       tcgetattr(0,&t);
       t.c_lflag&=~ECHO+~ICANON;
       tcsetattr(0,TCSANOW,&t);
       fflush(stdout);
       c=getchar();
       t.c_lflag|=ICANON+ECHO;
       tcsetattr(0,TCSANOW,&t);
       return c;
}

La libreria completa esta aqui: http://sourceforge.net/projects/libconio/
getchar en windows es lo que indicais, pero en linux las funciones de termios nos ayudan un pelin ;)
Por desgracia la funcion _kbhit no existe en esta libreria :(

Saludos
#9
General Programadores / frames por segundo en c++???
21 de Marzo de 2008, 09:35:34 PM
Yo tambien hacia las pruebas con el titulo de la ventana ya que es lo mas facil y comodo, pero realmente se nota muchisimo, lo mejor para que no se note tanto es cambiar solo el titulo de la ventana cada segundo y ademas si solo ha variado el contado de fps.
Lo que tampoco te recomiendo es usa los dispositivos de contexto del gdi, ya que por las pruebas que hice hace tiempo es incluso peor que lo del titulo de la ventana.

El codigo para mostrar los fps que suelo usar yo es este (realmente puede ser mas sencillo y mas basico):

// fps.h

// Por David Inclán Blanco
// http://www.davidib.com
// Este codigo esta protegido bajo licencia LGPL

#ifndef _v8_Time_FPS
#define _v8_Time_FPS

#include "../type/object.h"
#include "time.h"

namespace v8
{
namespace Time
{
/// <summary>Clase para calcular los FPS</summary>
class FPS : public v8::Type::Object
{
public:
/// <summary>Inicializar el contador de FPS</summary>
void Start()
{
this->fps = v8::Time::GetCurrent<unsigned int>();
this->maxFPS = this->fpsTemp = this->last = 0;
this->minFPS = 999999;
}

/// <summary>Calcular los FPS actuales</summary>
/// <returns>Numero de FPS actuales</returns>
unsigned int Calculate()
{
unsigned int current = v8::Time::GetCurrent<unsigned int>();
if( current - this->last >= 1000 )
{
this->last = current;
this->fps = this->fpsTemp;
this->fpsTemp = 0;
if( this->fps != 0 )
{
if( this->maxFPS < this->fps )
{
this->maxFPS = this->fps;
}
else
if( this->minFPS > this->fps )
{
this->minFPS = this->fps;
}
}
}
else
{
this->fpsTemp++;
}
return this->fps;
}

/// <summary>Obtener los FPS actuales</summary>
/// <returns>FPS actuales</summary>
unsigned int GetFPS()
{
return this->fps;
}

/// <summary>Obtener los FPS maximos</summary>
/// <returns>FPS maximos</returns>
unsigned int GetMaxFPS()
{
return this->maxFPS;
}

/// <summary>Obtener los FPS minimos</summary>
/// <returns>FPS minimos</returns>
unsigned int GetMinFPS()
{
return this->minFPS;
}

private:
/// <summary>FPS actuales</summary>
unsigned int fps;

/// <summary>FPS maximos</summary>
unsigned int maxFPS;

/// <summary>FPS minimos</summary>
unsigned int minFPS;

/// <summary>FPS temporal para calcular los FPS actuales</summary>
unsigned int fpsTemp;

/// <summary>Ultimos tiempo desde la llamada a CalculateFPS</summary>
unsigned int last;
};
}
}

#endif



// time.h

// Por David Inclán Blanco
// http://www.davidib.com
// Este codigo esta protegido bajo licencia LGPL

#ifndef _v8_Time_Time
#define _v8_Time_Time

#include <time.h>

namespace v8
{
namespace Time
{
/// <summary>Obtener el tiempo actual</summary>
/// <param name="TYPE">Tipo de dato en el que obtener el tiempo actual</param>
/// <remarks>1 segundo son 1000 ticks siempre</remarks>
/// <returns>Valor obtenido mediante la funcion clock()</returns>
template <class TYPE> TYPE GetCurrent()
{
#if CLOCKS_PER_SEC == 1000
return (TYPE)clock();
#else
return (TYPE)(clock() * ((TYPE)1000 / (TYPE)CLOCKS_PER_SEC));
#endif
}
}
}

#endif


Lo mejor es que cojas lo que quieras del codigo y lo uses a tu gusto.

Saludos
#10
General / ordenador nuevo
15 de Marzo de 2008, 12:35:09 PM
Los Dell son muy buenos salvo que tengas un problema con el ordenador, si esto te pasara, la atencion al cliente es pesima y te daran mil vueltas.
He comprado dos portatiles y un sobremesa, con los dos portatiles he tenido problemas y no me los han resuelto con el sobremesa me ha ido todo de perlas.
#11
IndieLib / 7 pruebas de LooverLib - Necesito testers
28 de Febrero de 2008, 07:52:11 PM
Intel(R) Core(TM)2 CPU T7200 2.00GHz
2046MB RAM
Windows Vista 32Bits
GeForce7900 256MB
(Es un portatil de hace un año)

01_Installing: ~3000fps
02_Ind_Surface: ~2000fps (petada al salir)
03_Ind_Image: ~1900fps (petada al salir)
04_IND_Animation: ~2000fps (petada al salir)
05_IND_Font: ~1200fps (petada al salir)
06_Primitives: ~700fps (petada al salir)
07_IND_Input: ~2400fps (petada al salir)

scaling: ~1200fps (petada al salir)

Puede que tengas un fallo en listas, pilas o en lo que estes usando para almacenar sprites, texturas, etc. ya que el 6 parece que no tiene texturas, pero sigue pentando; es solo una posibilidad tampoco me hagas mucho caso.
#12
General Programadores / Memory Leaks
02 de Enero de 2008, 07:27:15 PM
Hola,

tambien puedes implementarla tu mismo, en la ultima version de la libreria "multi-todo" que aun no he subido al web tengo una clase que sirve como reutilizador de memoria y depurador.
// garbage.h

// Por David Inclán Blanco
// http://www.davidib.com
// Este codigo esta protegido bajo licencia LGPL

#ifndef _dib_Memory_Garbage
#define _dib_Memory_Garbage

// Incluir cabeceras
#ifdef dib_Windows
#include <conio.h>
#endif

#include "memory.h"
#include "../type/object.h"
#include "../pattern/singleton.h"
#include "../io/log.h"

#define dib_Memory_Garbage_Name "Garbage"

namespace dib
{
namespace Memory
{
/// <summary>Permite reutilizar bloques de memoria previamente asignados acelerando la creacion y destruccion de objetos o zonas de memoria</summary>
/// <remarks>Si se indica dib_Debug se almacenaran en una lista las memorias que estan siendo usadas y de esta manera saber si no se ha liberado alguna de ellas</summary>
class Garbage : public dib::Type::Object
{
private:
/// <summary>Estructura prememoria</summary>
struct Head
{
/// <summary>Tamaño asignado</summary>
unsigned int size;
/// <summary>Numero de usos</summary>
unsigned int uses;
/// <summary>Siguiente memoria</summary>
Head* next;
#ifdef dib_Debug
/// <summary>Memoria anterior (solo se usa en la lista de memorias en uso)</summary>
Head* previous;
/// <summary>Nombre del archivo al que pertenece</summary>
const char* file;
/// <summary>Linea en este archivo</summary>
int line;
#endif
};

public:
/// <summary>Inicializar la clase</summary>
Garbage()
{
// Limpiar la tabla de memorias
Set( this->noUse, 0, sizeof(this->noUse) );
#ifdef dib_Debug
// Indicar que no hay ninguna memoria en uso
this->yesUse = null;
#endif
gLog->Write( dib_Memory_Garbage_Name, false, "Inicializado" );
}

/// <summary>Eliminar la clase</summary>
~Garbage()
{
// Eliminar todas las memorias sin uso
this->Clean( 0 );
#ifdef dib_Debug
// Si esta el modo debug activado mostrar las memorias usadas sin liberar
this->PrintMemoryUseds();
#endif
gLog->Write( dib_Memory_Garbage_Name, false, "Eliminado" );
}

/// <summary>Sumar un uso a una memoria</summary>
/// <param name="ptr">Puntero</param>
/// <remarks>Para eliminar uso se debe de llamar directamente a delete</remarks>
void AddRef( void* ptr )
{
Head* head = ((Head*)ptr) -1;
head->uses++;
}

/// <summary>Crear una nueva zona de memoria</summary>
/// <param name="size">Tamaño</param>
/// <param name="file">Nombre del archivo al que pertenece (solo con dib_Debug)
/// <param name="line">Linea en el archivo (solo con dib_Debug)
/// <returns>Nueva zona de memoria o null si no se ha podido crear</returns>
#ifdef dib_Debug
void* New( unsigned int size, const char* file, int line )
#else
void* New( unsigned int size )
#endif
{
// Mirar si existe alguna memoria en la tabla de memorias sin uso que se ajuste a las necesidades
int index = size % capacity;
Head* ret = *(this->noUse + index);
Head* previous = null;
while( ret != null )
{
if( ret->size == size )
{
// Tiene el mismo tamaño, nos vale perfectamente
if( previous != null )
{
// Esta por el medio
previous->next = ret->next;
}
else
{
// Es el primero
*(this->noUse + index) = ret->next;
}
#ifdef dib_Debug
InsertOnUsedMem( ret, file, line );
#endif
ret->uses = 0;
return (void*)(ret + 1);
}
// Siguiente
previous = ret;
ret = ret->next;
}
// No existe en la tabla de memorias asi que tenemos que crear una nueva
ret = (Head*)dib::Memory::Create( sizeof(Head) + size );
if( ret != null )
{
ret->size = size;
#ifdef dib_Debug
InsertOnUsedMem( ret, file, line );
#endif
ret->uses = 0;
return (void*)(ret + 1);
}
// Error al crear la memoria
return null;
}

/// <summary>Liberar una zona de memoria que ha sido creada con la funcion New de esta clase</summary>
/// <param name="ptr">Puntero a la zona de memoria</param>
void Delete( void* ptr )
{
if( ptr != null )
{
Head* head = ((Head*)ptr) -1;
if( head->uses <= 1 )
{
#ifdef dib_Debug
// Eliminarlo de la lista de las tablas de memoria en uso
if( head->previous != null )
{
// Esta por el medio
head->previous->next = head->next;
if( head->next != null )
{
head->next->previous = head->previous;
}
}
else
{
// Esta al inicio
this->yesUse = head->next;
if( this->yesUse != null )
{
this->yesUse->previous = null;
}
}
#endif
// Insertarlo al inicio de la tabla de memorias sin uso
unsigned int index = head->size % capacity;
head->next = *(this->noUse + index);
*(this->noUse + index) = head;
}
else
{
// Un uso menos
head->uses--;
}
}
}

/// <summary>Eliminar toda las zonas de memoria que no estan siendo usadas<summary>
/// <param name="size">Tamaño minimo de las zonas de memoria a eliminar</param>
/// <remarks>
/// Esta funcion elimina las memorias que no esten usadas, como parametro extra se le puede indicar que busque aquellos que superen o sean iguales al un tamaño dado, las demas
/// zonas de memoria no seran eliminadas, esto nos permite optimizar bastante ya que normalmente las zonas de memoria pequeñas suelen ser clases, variables normales, etc mientras
/// que las zonas de memoria grandes suelen ser imagenes, sonidos, etc que muy rara vez se reaprovecharan.
/// </reamrks>
void Clean( unsigned int size = 4096 )
{
Head* next;
// Recorrer toda la tabla hash
for( int n = 0; n < capacity; n++ )
{
// Recorrer la lista
while( this->noUse[n] != null )
{
if( this->noUse[n]->size < size )
{
// Siguiente
this->noUse[n] = this->noUse[n]->next;
}
else
{
next = this->noUse[n]->next;
// Liberar esta zona de memoria
dib::Memory::Delete( (void*)this->noUse[n] );
this->noUse[n] = next;
}
}
}
}

#ifdef dib_Debug
/// <summary>Mostrar las memorias que estan siendo usadas y no han sido liberadas</summary>
/// <param name="sizeSample">Tamaño de ejemplo a mostrar de la memoria</param>
void PrintMemoryUseds( unsigned int sizeSample = 32 )
{
if( this->yesUse != null )
{
Head* current = this->yesUse;
gLog->Write( dib_Memory_Garbage_Name, true, "Memoria sin liberar:" );
char* sample = (char*)dib::Memory::Create( sizeSample );
unsigned int size;
while( current != null )
{
// Copiar un ejemplo de la memoria
size = current->size < sizeSample ? current->size : sizeSample -1;
Copy( sample, (const void*)(current+1), size );
sample[size] = '\0';
// Mostrarlo
gLog->Write( null, false, "%s:%i (%i bytes / usado: %i): %s\n", current->file, current->line, current->size, current->uses, sample );
// Siguiente
current = current->next;
}
dib::Memory::Delete( (void*)sample );
printf( "Garbage: Hay memoria sin liberar\n" );
#ifdef dib_Windows
getch();
#endif
}
}
#endif

private:
#ifdef dib_Debug
/// <summary>Insertar una memoria al inicio de la lista de memorias en uso</summary>
/// <param name="head">Memoria a insertar</param>
/// <param name="file">Nombre del archivo al que pertenece (solo con dib_Debug)
/// <param name="line">Linea en el archivo (solo con dib_Debug)
void InsertOnUsedMem( Head* head, const char* file, int line )
{
head->file = file;
head->line = line;
head->previous = null;
head->next = this->yesUse;
if( this->yesUse != null )
{
this->yesUse->previous = head;
}
this->yesUse = head;
}
#endif

/// <summary>Enumeraciones</summary>
enum
{
/// <summary>Capacidad de las tablas hash en la clase</summary>
capacity = 16381,
};

/// <summary>Tabla hash donde se almacenan las zonas de memoria que NO estan siendo usadas</summary>
Head* noUse[capacity];

#ifdef dib_Debug
/// <summary>Lista enlazada con las zonas de memoria que si estan siendo usadas</summary>
Head* yesUse;
#endif
};
}
}

/// <summary>Instancia unica de la clase garbage</summary>
dib::Pattern::Singleton<dib::Memory::Garbage > gGarbage( true );

#ifdef dib_Debug
/// <summary>Operador new global</summary>
/// <param name="size">Tamaño de la memoria</param>
/// <param name="file">Nombre del fichero asociado a esta memoria</param>
/// <param name="line">Linea asociada del fichero</param>
/// <returns>Puntero a la memoria</returns>
void* __cdecl operator new( unsigned int size, const char* file, int line )
{
return gGarbage->New( size, file, line );
}
#define new new( __FILE__, __LINE__ )
#else
/// <summary>Operador new global</summary>
/// <param name="size">Tamaño de la memoria</param>
/// <returns>Puntero a la memoria</returns>
void* __cdecl operator new( unsigned int size )
{
return gGarbage->New( size );
}
#endif

/// <summary>Operador delete global</summary>
/// <param name="pointer">Puntero a la memoria que se quiere borrar</param>
void __cdecl operator delete( void* pointer )
{
return gGarbage->Delete( pointer );
}

#endif _dib_Memory_Garbage

Parece muy complicado al principio, pero realmente es muy sencillo de leer el codigo si se le dedica unos minutos.
El modo reutilizador de memoria funciona con todos los compiladores que he probado (gcc, vc++), el reutilizador de memoria + depurador solo lo he probado con el vc++, pero si existen las constantes __FILE__ y __LINE__ no deberia de dar problemas.

Tambien existe otra clase que aun no he probado mucho ya que la hice casi al final de terminar la libreria, es una clase de punteros "inteligentes" que libera la memoria solo cuando es necesario (numero de usos), realmente es complementaria, es decir, no es requerida para que funcione la clase del reutilizador de memoria + depurador.

// ptr.h

// Por David Inclán Blanco
// http://www.davidib.com
// Este codigo esta protegido bajo licencia LGPL

#ifndef _dib_Memory_ptr
#define _dib_Memory_ptr

#include "garbage.h"

//namespace dib
//{
// namespace Memory
// {
/// <summary>Clase que permite trabajar con punteros inteligentes</summary>
template <class TYPE> class ptr
{
public:
/// <summary>Inicializar el puntero con null</summary>
ptr()
{
this->mem = null;
}

/// <summary>Inicializar el puntero con una zona de memoria creada con new</summary>
/// <param name="mem">Memoria</param>
ptr( TYPE* mem )
{
this->mem = null;
this->SetMem( mem );
}

/// <summary>Indicar la memoria a usar con este puntero</summary>
/// <param name="mem">Memoria</param>
ptr& operator = ( TYPE* mem )
{
this->SetMem( mem );
return *this;
}

/// <summary>Indicar la memoria a usar con este puntero</summary>
/// <param name="pointer">Clase puntero</param>
ptr& operator = ( ptr& pointer )
{
this->SetMem( pointer.mem );
return *this;
}

/// <summary>Obtener contenido del puntero</summary>
void* operator * ()
{
return this->mem;
}

private:
/// <summary>Indicar la memoria</summary>
/// <param name="mem">Memoria</param>
void SetMem( TYPE* mem )
{
// Quitar un uso
delete this->mem;
if( mem != null )
{
gGarbage->AddRef( mem );
this->mem = mem;
}
}

/// <summary>Memoria en uso</summary>
TYPE* mem;
};
// }
//}

#endif

Saludos[/code]
#13
General / ¿Por qué Linux es mejor que Windows?
30 de Abril de 2007, 07:26:18 PM
No se si ya se ha mencionado, pero comparar linux y windows no se puede ya que linux no es un entorno grafico de por si, mas bien aqui parece que se debate gnome, kde, etc contra windows (por eso lo digo).

La mayor diferencia entre windows y linux es que las aplicaciones en windows siempre se hacen con un interfaz de usuario (salvo excepciones claro esta) y las de linux se basan en linea de comandos para luego si se quiere hacer una aplicacion con intefaz de usuario que llama a la de linea de comando, no se si se me entiende, pero son filosofias diferentes.

Ahora bien para entorno grafico sin duda me quedo con windows, ahora claro esta, para administrar un sistema muchas veces (la verdad es que siempre) es mejor la linea de comandos.
#14
Bueno solo posteaba para decir que me ha llegado el portatil inspiron 9400 con vista y la verdad es que mi primer contacto con vista no ha sido muy alentador, es muy rapido y fluido, pero chupa memoria por un tubo, 1 giga nada mas arrancarlo, por suerte siempre instalo desde cero los ordenadores cuando me vienen nuevos y ahora solo chupa 500MB, solo decir que en el sobremesa el test de los conejos que hice hace tiempo a una resolucion de 1024x768 me daba 12000 conejos y el portatil con esa resolucion 18000 que no esta nada mal :), lo he probado a subir a 1920x1200 que es la resolucion maxima y mi sorpresa es que da 17000 conejos ;)
#15
Es con IVA, me pille la de 6 celas ya que yo tengo enchufes a mano aunque lo mueva y la uso mas que nada como una sai, la bateria con 9 celdas son 29 euros mas.

Por si a alguien le interesa: http://configure2.euro.dell.com/dellstore/config.aspx?b=&c=es&cs=esdhs1&kc=N4XXPS02&l=es&oc=N04947&rbc=N04947&s=dhs&sbc=esdhsftdppnotebook2





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.