Gracias Gracias:  1
Página 1 de 2 12 ÚltimoÚltimo
Resultados 1 al 15 de 20

Tema: Busco ayuda para desarrollar video juego diseñadores, modeladores, musicos

  1. #1
    Miembro Nuevo
    Fecha de ingreso
    Jul 2011
    Mensajes
    17

    Busco ayuda para desarrollar video juego (diseñadores, modeladores, músicos)

    Hola,

    ¿Alguien ha jugado Dungeon Keeper alguna vez? Tengo una idea para crear un juego de estrategia/rompecabezas, que se juega por turnos, no en tiempo real, donde el jugador controla un grupo de caballeros, y estos deben atravesar un castillo esquivando las trampas que encuentren en su camino. Los caballeros se mueven como piezas en un tablero. La idea es hacerlo sencillo, divertido y especialmente adictivo.

    El proyecto inicialmente no es remunerado, pero si es necesario yo puedo hacer toda la parte de programación, montaje de la interfaz, y los efectos (fuego, explosiones, y otras partículas). La idea es vender el juego en la Web, y que entremos en una sociedad para repartir las ganancias según el porcentaje de trabajo de los miembros del equipo. Ya tengo arreglado el asunto de los pagos por Internet.

    El plan inicial es el siguiente:

    1. Reclutar diseñadores que creen la interfaz del juego. Pueden trabajar en Photoshop o Fireworks, yo me encargaría de recortar todo y montarlo con CSS3. Para comenzar hay que diseñar:
    1.1. Pagina de inicio de la web
    1.2. Pagina de registro de jugadores
    1.3. Pagina del cliente del juego
    1.4. Interfaz del jugador

    2. Reclutar modeladores 3D que creen personajes y armas. Todos los personajes deben tener animación de caminata, ataque y muerte. Para comenzar hay que modelar:
    2.1. Caballero sin armadura, ligero pero vulnerable
    2.2. Caballero con armadura ligera
    2.3. Caballero con armadura pesada, lento pero resistente
    2.4. Y algunos monstruos, como dragones, lobos, etc. Podemos decidirlo más adelante.

    3. Reclutar músicos para las tonadas de fondo. La música debe ser de suspenso, y necesitamos ayuda con los efectos de sonido, gritos, etc.

    Espero que les guste la idea, anímense a participar. Mi correo es marcoantap@gmail.com . Si tienen alguna pregunta urgente pueden contactarme por Skype con la cuenta "marcoantap".

    NUEVO! Galería del proyecto: http://wcu.co/N_

    ¡Saludos!
    -Marco
    Última edición por marcoantap; 23-08-2011 a las 19:15
    PROYECTOS
    CastleQuest, galería: http://wcu.co/N_
    ¿Consultas de desarrollo de vjuegos? marcoantap@gmail.com

  2. #2
    Expulsado
    Fecha de ingreso
    Dec 2010
    Ubicación
    En matrix
    Mensajes
    1,681

    Re: Busco ayuda para desarrollar video juego (diseñadores, modeladores, músicos)

    umm, creo que deverias olvidarte de página web de momento y centrarte en el juego en si. Pero es solo mi opinión. Suerte.

  3. #3
    Miembro Nuevo
    Fecha de ingreso
    Jul 2011
    Mensajes
    17

    Thumbs up Re: Busco ayuda para desarrollar video juego (diseñadores, modeladores, músicos)

    Gracias aprendiz. Ciertamente el juego es lo más importante, pero ya estoy trabajando en éste. Toma un poco de tiempo armar un equipo, así que para cuando las gráficas y la música estén listas, ya habré acabado y tendré tiempo de construir la web según el diseño.

  4. #4
    Miembro Nuevo
    Fecha de ingreso
    Jul 2011
    Mensajes
    17

    Re: Busco ayuda para desarrollar video juego (diseñadores, modeladores, músicos)

    Gracias aprendiz. Ciertamente el juego es lo más importante, pero ya estoy trabajando en éste, por el lado de la programación. Formar un grupo de trabajo lleva tiempo, así que para cuando los diseños estén listos podré construir la página web, por eso la estoy planeando por adelantado.

  5. #5
    Expulsado
    Fecha de ingreso
    Dec 2010
    Ubicación
    En matrix
    Mensajes
    1,681

    Re: Busco ayuda para desarrollar video juego (diseñadores, modeladores, músicos)

    Ya, cada uno tiene su modo de trabajo..por cierto, en que lenguaje/motor lo estas programando?

  6. #6
    Miembro Nuevo
    Fecha de ingreso
    Jul 2011
    Mensajes
    17

    Thumbs up Re: Busco ayuda para desarrollar video juego (diseñadores, modeladores, músicos)

    Pues primero te cuento mis antecedentes en este mundo de la programación. Llevo varios años desarrollando, y ya he acumulado más de 5 años en Flash AS2/AS3, 2 años en Unity3D, y anteriormente trabajé en Blitz3D durante un par de años, pero lo dejé cuando salió BlitzPlus. Por otro lado he programado con las APIs DirectX y OpenGL, mediante C++ (Visual Studio) y Object Pascal (Lazarus/FPC/Delphi). También tengo varios años trabajando en PHP y Java para las aplicaciones del servidor. Hoy en día me divierto programando en HTML5 y su Canvas. Vengo de la era del DOS, cuando programabas las tarjetas EGA con Assembly x86 y te rompias la cabeza pensando en 4 planos de color. Todavía conservo algunas de mis bibliotecas open-source aquí:

    http://gamelix.com/opensource/

    En Unity3D hice una herramienta para comúnicar Flash con Unity, por medio de Javascript:

    http://forum.unity3d.com/threads/187...Unity-Flash%29

    Y volviendo a tu pregunta, estuve pensando en hacer el juego en HTML5, porque quiero que corra en el iPad, pero no quiero irme por el iTunes. Sin embargo me pone a dudar el asunto de la obfuscación del código, porque pueden hackear los mapas del juego y no hay mucha confianza en la comunicación cliente-servidor. Entonces me fuí por Unity, con el que es más fácil lograr un resultado profesional. Cuando el juego esté listo creo que voy a hacer una versión móvil para los iPad en HTML5.

  7. #7
    Expulsado
    Fecha de ingreso
    Dec 2010
    Ubicación
    En matrix
    Mensajes
    1,681

    Re: Busco ayuda para desarrollar video juego (diseñadores, modeladores, músicos)

    Bufff, bonita historia digna de recordar,jeje. Algun día llegare a tanto,jaja. Yo de momento estoy con blitz3d, hay to feliz. Más adelante me pondré en serio con directx o Opengl (seguramente opengl). Bueno, pues sabiendo todo eso también podrás hacer lo que quieras, así que no vas a necesitar suerte, :D

  8. #8
    Miembro Nuevo
    Fecha de ingreso
    Jul 2011
    Mensajes
    17

    Re: Busco ayuda para desarrollar video juego (diseñadores, modeladores, músicos)

    Pues yo estaba husmeando en el tema que abriste al lado, y me parece que tienes un nivel bastante bueno Antes uno perdía mucho tiempo descubriendo como poner un punto en la pantalla, con las tecnologías de ahora te puedes dedicar a lo que originalmente querías hacer: desarrollo de video juegos. Si me pidieras un consejo te diría que no te metas con DirectX ó OpenGL, mejor trata de saltar a la siguiente tecnología más moderna, digamos cosas para dispositivos móviles, y que te permita trabajar de la manera más sencilla y rápida posible. En este momento estaríamos hablando de Unity3D, mañana quien sabe que saldrá. Y si quieres irte al bajo nivel, puedes aprender las tecnologías de redes (protocolos, encriptación de transmisiones, etc.). Te digo esto, porque muchas veces cuando yo terminaba de dominar una tecnología, la siguiente aparecía y todo mi trabajo se volvía obsoleto. Además, guarda imágenes y videos de todo lo que hagas. Aunque los motores dejen de correr, cuando quieras buscar un empleo en el área, buscar inversiónistas para tus proyectos, o simplemente rememorar tus trabajos, todas estas muestras se volveran muy muy útiles. Bueno, eso es lo que yo haría si volviera en el tiempo jejeje

  9. #9
    Expulsado
    Fecha de ingreso
    Dec 2010
    Ubicación
    En matrix
    Mensajes
    1,681

    Re: Busco ayuda para desarrollar video juego (diseñadores, modeladores, músicos)

    Bueno se hace lo que se puede, de momento sin ánimo de lucro, y por el único objetivo de aprender.:D
    Gracias por el consejo, pero me apasionan los bajos niveles, no por otra razón que la de comprender...si pudiera seguiria estudiando desde el transistor hasta como funciona un microprocesador,jaja (que de hecho lo he echo, pero devido a los costes que supone el desarrollo con componentes físicos, me pase a la programación en donde haces todo con un solo programa, aunque algún día retomare los circuitos).
    Gracias también por lo de guardar videos etc, seguiré el consejo !!

    Y respecto a lo de que tu trabajo se vuelve obsoleto, en cierto modo si, pero lo que aprendiste mientras desarrollabas proyectos antiguos nadie te lo quita, y en la programación lo que más cuenta es la logica/practica que vas cogiendole...que cambian los codigos...bueno, se aprenden las instruciones nuevas pero la lógica la sigues teniendo, así que no hiciste nada en vano (de hecho nunca se hace nada en vano), y más sabiendo tantos lenguajes como sabes, :D

  10. #10
    Miembro Nuevo
    Fecha de ingreso
    Jul 2011
    Mensajes
    17

    Lightbulb Re: Busco ayuda para desarrollar video juego (diseñadores, modeladores, músicos)

    Parece que estamos hablando el mismo idioma. Yo también estudié micro-electrónica, pero programar siempre ha sido mi pasión, y además resultó ser más rentable.

    Bueno, si tanto te interesa la programación de bajo nivel te recomiendo el FPC: http://www.freepascal.org/

    Es tan poderoso como C++, pero Pascal es más amable con el programador. Especialmente si te mueves de Basic a Pascal, te será mucho más fácil. Y si alguna vez te animas a trabajar con DX y OGL, tal vez quieras darme una mano con un motor que he venido creando desde hace varios años, y que ya he probado en Windows, MacOS y Linux. Este es el módulo de inicialización gráfico, para que te hagas una idea de la sintaxis:

    Código:
    //==============================================================================
    // Escenas.pas (ec_)
    // Copyright (c) 2009 Marco Antonio Alvarado Pérez
    //
    // Lenguaje: Object Pascal (FPC)
    // Define las estructuras de la escena y su flujo de pintado.
    //==============================================================================
    
    {$INCLUDE Opciones.inc}
    
    unit Escenas;
    
    {$mode objfpc}{$H+}
    
    interface
    
    uses
    {$IFDEF GRF_DIRECTX}
    // Clootie DirectX Headers
     Direct3D9, D3DX9,
    {$ENDIF}
    {$IFDEF GRF_OPENGL}
    // OpenGL
     OpenGLContext, GL, GLU, GLext,
    {$ENDIF}
     Classes, SysUtils,
    // Morpho
     Depuracion, Textos, Cálculos, Gráficos, Transferencias, Interpretes, Colores,
     Medios, Objetos, Datos, imágenes, Recursos, Interfases;
    
    type
     ec_cBoceto = class;
     ec_cObjetoEscena = class;
    
     { ec_cPintor }
    
     ec_cPintor = class
     public
     procedure PintaBoceto(const Boceto: ec_cBoceto); virtual;
     end;
    
     { ec_cPintorControl }
    
     ec_cPintorControl = class(ec_cPintor)
     public
     procedure PintaBoceto(const Boceto: ec_cBoceto); override;
     end;
    
     { ec_cTrazo }
    
     ec_cTrazo = class
     public
     Transformación: gf_rMatriz4x4;
     Texturas: md_arTextura;
     FiltrosTexturas: md_aeFiltroTextura;
     end;
    
     ec_pcTrazo = ^ec_cTrazo;
     ec_acTrazo = array of ec_cTrazo;
    
     { ec_cTrazoPlano }
    
     ec_cTrazoPlano = class(ec_cTrazo)
     public
     Vertices: gf_arVerticePlano;
     end;
    
     { ec_cBoceto }
    
     ec_cBoceto = class
     public
     Trazos: ec_acTrazo;
     Pintor: ec_cPintor;
     constructor Create(const _Pintor: ec_cPintor);
     destructor Destroy; override;
     procedure Pinta;
     end;
    
     ec_pcBoceto = ^ec_cBoceto;
     ec_acBoceto = array of ec_cBoceto;
    
     { ec_cBocetoControl }
    
     ec_cBocetoControl = class(ec_cBoceto)
     public
     procedure Boceta(const Control: if_cObjetoControl; const Transformación:
     gf_rMatriz4x4; out Visible, Toque: Boolean);
     end;
    
     { ec_cObjetoEscena }
    
     ec_cObjetoEscena = class(oj_cObjeto)
     public
     PintorControl: ec_cPintorControl;
     Bocetos: ec_acBoceto;
     Fondo: cl_rA8R8G8B8;
     constructor Create; override;
     destructor Destroy; override;
     procedure Actualiza;
     end;
    
    var
     ec_ClaseEscena: UCS4String;
    
    implementation
    
    uses
    // Morpho
     Aplicaciones;
    
    //------------------------------------------------------------------------------
    { ec_cPintor }
    //------------------------------------------------------------------------------
    
    //------------------------------------------------------------------------------
    procedure ec_cPintor.PintaBoceto(
     const Boceto: ec_cBoceto
     );
    begin
     if Boceto = nil then ;
    // Implementado por los descendientes.
    end;
    
    //------------------------------------------------------------------------------
    { ec_cPintorControl }
    //------------------------------------------------------------------------------
    
    //------------------------------------------------------------------------------
    procedure ec_cPintorControl.PintaBoceto(
     const Boceto: ec_cBoceto
     );
    
    var
     Trazo, FinTrazo: ec_pcTrazo;
     Textura, FinTextura: md_prTextura;
     ITextura: LongInt;
     FiltroTextura: md_peFiltroTextura;
     _Trazo: ec_cTrazoPlano;
    {$IFDEF GRF_DIRECTX}
     Dispositivo: IDirect3DDevice9;
     Capacidades: TD3DCaps9;
    {$ENDIF}
    {$IFDEF GRF_OPENGL}
     Vertice, FinVertice: gf_prVerticePlano;
    {$ENDIF}
    
    begin
     if not (Boceto is ec_cBoceto) or (Length(Boceto.Trazos) <= 0) then
     Exit;
    
     Trazo := @Boceto.Trazos[0];
     FinTrazo := @Boceto.Trazos[Length(Boceto.Trazos)];
    
     while Trazo < FinTrazo do
     begin
     ec_cTrazo(_Trazo) := Trazo^;
    
     if Length(_Trazo.Vertices) <= 0 then
     begin
     Trazo += 1;
     Continue;
     end;
    
    {$IFDEF GRF_DIRECTX}
     Dispositivo := ap_Aplicacion.Pantalla.Dispositivo;
     Dispositivo.GetDeviceCaps(Capacidades);
     Dispositivo.BeginScene;
    
    // Desactiva la luz y la prueba de profundidad.
     Dispositivo.SetRenderState(D3DRS_LIGHTING, LongWord(False));
     Dispositivo.SetRenderState(D3DRS_ZENABLE, LongWord(False));
    
    // Activa la transparencia, e impide que los puntos con alfa < 1 se dibujen.
     Dispositivo.SetRenderState(D3DRS_ALPHABLENDENABLE, LongWord(True));
     Dispositivo.SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
     Dispositivo.SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
     Dispositivo.SetRenderState(D3DRS_ALPHATESTENABLE, LongWord(False));
    { /!\ No parece necesario /!\
     Dispositivo.SetRenderState(D3DRS_ALPHATESTENABLE, LongWord(True));
     Dispositivo.SetRenderState(D3DRS_ALPHAREF, 1);
     Dispositivo.SetRenderState(D3DRS_ALPHAFUNC, D3DCMP_GREATEREQUAL); }
    
     if Length(_Trazo.Texturas) > 0 then
     begin
     Textura := @_Trazo.Texturas[0];
     FinTextura := @_Trazo.Texturas[Length(_Trazo.Texturas)];
     ITextura := 0;
     FiltroTextura := @_Trazo.FiltrosTexturas[0];
    
     while Textura < FinTextura do
     begin
     Dispositivo.SetTexture(ITextura, Textura^.Textura);
    
    // Establece el tratamiento de color de la textura.
     Dispositivo.SetTextureStageState(ITextura, D3DTSS_COLOROP,
     D3DTOP_MODULATE);
     Dispositivo.SetTextureStageState(ITextura, D3DTSS_COLORARG1,
     D3DTA_TEXTURE);
     Dispositivo.SetTextureStageState(ITextura, D3DTSS_COLORARG2,
     D3DTA_DIFFUSE);
     Dispositivo.SetTextureStageState(ITextura, D3DTSS_ALPHAOP,
     D3DTOP_SELECTARG1);
     Dispositivo.SetTextureStageState(ITextura, D3DTSS_ALPHAARG1,
     D3DTA_TEXTURE);
    
    // Establece el filtro de suavizamiento de las texturas con la distancia.
     if FiltrosTextura^ = md_FILTRO_TEXTURA_LINEAL then
     begin
     Dispositivo.SetSamplerState(ITextura, D3DSAMP_MINFILTER,
     D3DTEXF_LINEAR);
     Dispositivo.SetSamplerState(ITextura, D3DSAMP_MAGFILTER,
     D3DTEXF_LINEAR);
     Dispositivo.SetSamplerState(ITextura, D3DSAMP_MIPFILTER,
     D3DTEXF_LINEAR);
     end
     else
     begin
     Dispositivo.SetSamplerState(ITextura, D3DSAMP_MINFILTER, D3DTEXF_NONE
     );
     Dispositivo.SetSamplerState(ITextura, D3DSAMP_MAGFILTER, D3DTEXF_NONE
     );
     Dispositivo.SetSamplerState(ITextura, D3DSAMP_MIPFILTER, D3DTEXF_NONE
     );
     end;
    
    // Establece la extensión de las texturas.
     Dispositivo.SetSamplerState(ITextura, D3DSAMP_ADDRESSU, D3DTADDRESS_WRAP
     );
     Dispositivo.SetSamplerState(ITextura, D3DSAMP_ADDRESSV, D3DTADDRESS_WRAP
     );
    
    // Activa las transformaciónes para las coordenadas 2D de las texturas.
     Dispositivo.SetTextureStageState(ITextura, D3DTSS_TEXTURETRANSFORMFLAGS,
     D3DTTFF_COUNT2);
     Textura += 1;
     ITextura += 1;
     FiltroTextura += 1;
     end;
    
     end;
    
    // Establece las transformaciónes.
     Dispositivo.SetTransform(D3DTS_WORLD, TD3DMatrix(_Trazo.Transformación));
    
    // Dibuja el cuadro con el diseño en Z para DirectX.
     Dispositivo.SetFVF(gf_FORMATO_VERTICE_PLANO);
     Dispositivo.DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, Length(_Trazo.Vertices),
     _Trazo.Vertices[0], SizeOf(gf_rVerticePlano));
    
     Dispositivo.EndScene;
    {$ENDIF}
    
    {$IFDEF GRF_OPENGL}
    // Desactiva la luz y la prueba de profundidad.
     glDisable(GL_LIGHTING);
     glDisable(GL_DEPTH_TEST);
    
    // Activa la transparencia, e impide que los puntos con alfa < 0.1 se dibujen.
     glEnable(GL_TEXTURE_2D);
     glEnable(GL_BLEND);
     glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
     glDisable(GL_ALPHA_TEST);
    { /!\ No parece necesario /!\
     glEnable(GL_ALPHA_TEST);
     glAlphaFunc(GL_GREATER, 0.1); }
    
     if Length(_Trazo.Texturas) > 0 then
     begin
     Textura := @_Trazo.Texturas[0];
     FinTextura := @_Trazo.Texturas[Length(_Trazo.Texturas)];
     ITextura := 0;
     FiltroTextura := @_Trazo.FiltrosTexturas[0];
    
     while Textura < FinTextura do
     begin
     glBindTexture(GL_TEXTURE_2D, Textura^.Textura);
    
    // Establece el tratamiento de color de la textura.
    // glActiveTexture(GL_TEXTURE0+ITextura); // glActiveTexture = nil? 
     glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
     glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE);
     glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_TEXTURE);
     glTexEnvf(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
     glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_REPLACE);
     glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_TEXTURE);
     glTexEnvf(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
    
    // Establece el filtro de suavizamiento de las texturas con la distancia.
     if FiltroTextura^ = md_FILTRO_TEXTURA_LINEAL then
     begin
     glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
     GL_LINEAR_MIPMAP_LINEAR);
     glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
     end
     else
     begin
     glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
     glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
     end;
    
    // Establece la extensión de las texturas.
     glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
     glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
     Textura += 1;
     ITextura += 1;
     FiltroTextura += 1;
     end;
    
     end;
    
    // Establece las transformaciónes.
     glMatrixMode(GL_PROJECTION);
     glLoadIdentity;
     glOrtho(0, ap_Aplicacion.Pantalla.Ancho, ap_Aplicacion.Pantalla.Alto, 0, 0,
     1);
     glMatrixMode(GL_MODELVIEW);
     glLoadMatrixf(@_Trazo.Transformación);
    
     if Length(_Trazo.Vertices) > 0 then
     begin
    // Dibuja el cuadro cambiando el diseño en Z para DirectX, por uno de reloj.
     glBegin(GL_QUADS);
     Vértice := @_Trazo.Vertices[0];
     FinVertice := @_Trazo.Vertices[Length(_Trazo.Vertices)];
    
     while Vértice < FinVertice do
     begin
     glTexCoord2f(Vertice^.T.X, Vertice^.T.Y);
     glVertex2f(Vertice^.P.X, Vertice^.P.Y);
     Vértice += 1;
     end;
    
     end;
    
     glEnd;
    {$ENDIF}
    
     Trazo += 1;
     end;
    
    end;
    
    //------------------------------------------------------------------------------
    { ec_cBoceto }
    //------------------------------------------------------------------------------
    
    //------------------------------------------------------------------------------
    constructor ec_cBoceto.Create(
     const _Pintor: ec_cPintor
     );
    begin
     inherited Create;
    
     Pintor := _Pintor;
    end;
    
    //------------------------------------------------------------------------------
    destructor ec_cBoceto.Destroy;
    
    var
     Trazo, FinTrazo: ec_pcTrazo;
    
    begin
    
     if Length(Trazos) > 0 then
     begin
     Trazo := @Trazos[High(Trazos)];
     FinTrazo := @Trazos[0];
    
     while Trazo >= FinTrazo do
     begin
     Trazo^.Free;
     Trazo -= 1;
     end;
    
     end;
    
     inherited;
    end;
    
    //------------------------------------------------------------------------------
    procedure ec_cBoceto.Pinta;
    begin
     Pintor.PintaBoceto(Self);
    end;
    
    //------------------------------------------------------------------------------
    { ec_cBocetoControl }
    //------------------------------------------------------------------------------
    
    //------------------------------------------------------------------------------
    procedure ec_cBocetoControl.Boceta(
     const Control: if_cObjetoControl;
     const Transformación: gf_rMatriz4x4;
     out Visible,
     Toque: Boolean
     );
    
    var
     Fuente: if_cObjetoFuente;
     MargenIzquierda, MargenArriba, MargenDerecha, MargenAbajo, Espaciado,
     BordeIzquierda, BordeArriba, BordeDerecha, BordeAbajo: Extended;
     AnchoTexto, AltoTexto, AltoOpcion, BordeOpcion: Extended;
     Imagen, ImagenFuente: im_cImagen;
     _Imagen: rc_cObjetoImagen;
     Cuadros: oj_acEnlace;
     Cuadro: if_cObjetoCuadro;
     X1, X2, X3, X4, Y1, Y2, Y3, Y4, XT, YT: Extended;
     Trazo: ec_cTrazoPlano;
     EOpcion, EFinOpcion: oj_pcEnlace;
     opción: if_cObjetoOpcion;
     Nodo: dt_cObjetoNodo;
    
    //------------------------------------------------------------------------------
     procedure AgregaTrazo;
    
     var
     ITrazo: LongInt;
    
     begin
     Trazo := ec_cTrazoPlano.Create;
     Trazo.Transformación := Control.Transformación;
     ITrazo := Length(Trazos);
     SetLength(Trazos, ITrazo+1);
     Trazos[ITrazo] := Trazo;
     end;
    
    //------------------------------------------------------------------------------
     procedure AgregaTextura(
     const Imagen: im_cImagen
     );
    
     var
     ITextura: LongInt;
    
     begin
     if not (Imagen is im_cImagen) then
     Exit;
    
     ITextura := Length(Trazo.Texturas);
     SetLength(Trazo.Texturas, ITextura+1);
     SetLength(Trazo.FiltrosTexturas, ITextura+1);
     Trazo.Texturas[ITextura] := Imagen.GeneraTextura;
     Trazo.FiltrosTexturas[ITextura] := md_eFiltroTextura(Control.Filtro.Valor);
     end;
    
    //------------------------------------------------------------------------------
     procedure AgregaCuadro(
     const Cuadro: oj_cObjeto;
     const X1, Y1, X2, Y2: Extended
     );
    
     var
     _Cuadro: if_cObjetoCuadro;
    
     begin
     if not (Cuadro is if_cObjetoCuadro) then
     	Exit;
    
     oj_cObjeto(_Cuadro) := Cuadro;
     gf_AgregaCuadroPlano(X1, Y1, X2-X1, Y2-Y1, _Cuadro.X.Valor, _Cuadro.Y.
     Valor, _Cuadro.Ancho.Valor, _Cuadro.Alto.Valor, Imagen.TomaAncho,
     Imagen.TomaAlto, nil, nil, Trazo.Vertices);
     end;
    
    //------------------------------------------------------------------------------
     procedure AgregaTexto(
     const Texto: UCS4String;
     X, Y: Extended
     );
    
     var
     STexto, SFinTexto: PUCS4Char;
     Ancho, Ascenso, Alto: Extended;
     _Simbolo: if_cObjetoSimbolo;
    
     begin
     if Length(Texto) <= 0 then
     Exit;
    
     STexto := @Texto[0];
     SFinTexto := @Texto[Length(Texto)];
    
     while STexto < SFinTexto do
     begin
     _Simbolo := Fuente.BuscaSimbolo(STexto^);
    
     if not (_Simbolo is if_cObjetoSimbolo) then
     begin
     STexto += 1;
     Continue;
     end;
    
     Ancho := _Simbolo.Ancho.Valor;
     Ascenso := _Simbolo.Ascenso.Valor;
     Alto := Ascenso+_Simbolo.Descenso.Valor;
     gf_AgregaCuadroPlano(X, Y-Ascenso, Ancho, Alto, _Simbolo.X.Valor,
     _Simbolo.Y.Valor-Ascenso, Ancho, Alto, Imagen.TomaAncho, Imagen.
     TomaAlto, nil, nil, Trazo.Vertices);
     if Boolean(Fuente.Proporcional.Valor) then
     X += Ancho+Fuente.Espaciado.Valor
     else
     X += Fuente.Ancho.Valor+Fuente.Espaciado.Valor;
     STexto += 1;
     end;
    
     end;
    
    //------------------------------------------------------------------------------
     procedure AgregaNodo(
     const Nodo: dt_cObjetoNodo;
     const Atributo: UCS4String;
     const X: Extended;
     var Y: Extended;
     const Ancho, Alto: Extended
     );
    
     var
     ENodo, EFinNodo: oj_pcEnlace;
     _Nodo: dt_cObjetoNodo;
    
     begin
     if not (Nodo is dt_cObjetoNodo) or (Length(Nodo.Nodos.Referencias) <= 0)
     	then
     Exit;
    
     ENodo := @Nodo.Nodos.Referencias[0];
     EFinNodo := @Nodo.Nodos.Referencias[Length(Nodo.Nodos.Referencias)];
    
     while ENodo < EFinNodo do
     begin
     if Y > Alto then
     Break;
    
     oj_cObjeto(_Nodo) := ENodo^.Objeto;
    
     if not (_Nodo is dt_cObjetoNodo) then
     begin
     ENodo += 1;
     Continue;
     end;
    
     AgregaTexto(_Nodo.TomaAtributo(Atributo, nil), X, Y);
     Y += AltoOpcion;
     AgregaNodo(_Nodo, Atributo, X+Espaciado, Y, Ancho, Alto);
     ENodo += 1;
     end;
    
     end;
    
    begin
     Visible := False;
     Toque := False;
     if not (Control is if_cObjetoControl) then
     Exit;
    
     if if_ExtraeEstado(Control.Tema.Valor, Control.Aspecto.Valor, Control.
     Estado.Valor, MargenIzquierda, MargenArriba, MargenDerecha, MargenAbajo,
     Espaciado, BordeIzquierda, BordeArriba, BordeDerecha, BordeAbajo, Imagen,
     Cuadros, Fuente, ImagenFuente) = False then
     begin
    
     if Control is if_cObjetoCursor then
     begin
     if Boolean(if_cObjetoCursor(Control).Visible.Valor) = False then
     md_OcultaCursor
     else
     md_MuestraCursor(md_EvaluaCursor(if_cObjetoCursor(Control).Aspecto.
     Valor));
     end;
    
     Exit;
     end;
    
     if Control is if_cObjetoCursor then
     begin
    
     if Boolean(Control.Visible.Valor) then
     begin
     if Length(Cuadros) < 1 then
     Exit;
    
     Control.Transformación := gf_Multiplica(Transformación,
     gf_CreaMatriz4x4Traslada(ap_Aplicacion.Entrada.XCursor, ap_Aplicacion.
     Entrada.YCursor, 0, False));
     Visible := True;
    
     AgregaTrazo;
     AgregaTextura(Imagen);
     oj_cObjeto(Cuadro) := Cuadros[0].Objeto;
     X1 := -BordeIzquierda;
     Y1 := -BordeArriba;
     X2 := X1+Cuadro.Ancho.Valor;
     Y2 := Y1+Cuadro.Alto.Valor;
     AgregaCuadro(Cuadro, X1, Y1, X2, Y2);
    
     md_OcultaCursor;
     end
     else
     begin
     md_MuestraCursor(md_CURSOR_NORMAL);
     end;
    
     end
     else if Control is if_cObjetoPanel then
     begin
    
     if Boolean(Control.Visible.Valor) then
     begin
     if Length(Cuadros) < 9 then
     Exit;
    
     Control.Transformación := gf_Multiplica(Transformación,
     gf_CreaMatriz4x4Traslada(if_cObjetoPanel(Control).X.Valor,
     if_cObjetoPanel(Control).Y.Valor, 0, False));
     Visible := True;
    
     AgregaTrazo;
     AgregaTextura(Imagen);
     oj_cObjeto(Cuadro) := Cuadros[0].Objeto;
     X1 := -BordeIzquierda;
     Y1 := -BordeArriba;
     X2 := X1+Cuadro.Ancho.Valor;
     Y2 := Y1+Cuadro.Alto.Valor;
     oj_cObjeto(Cuadro) := Cuadros[8].Objeto;
     X4 := if_cObjetoPanel(Control).Ancho.Valor+BordeDerecha;
     Y4 := if_cObjetoPanel(Control).Alto.Valor+BordeAbajo;
     X3 := X4-Cuadro.Ancho.Valor;
     Y3 := Y4-Cuadro.Alto.Valor;
     AgregaCuadro(Cuadros[0].Objeto, X1, Y1, X2, Y2);
     AgregaCuadro(Cuadros[1].Objeto, X2, Y1, X3, Y2);
     AgregaCuadro(Cuadros[2].Objeto, X3, Y1, X4, Y2);
     AgregaCuadro(Cuadros[3].Objeto, X1, Y2, X2, Y3);
     AgregaCuadro(Cuadros[4].Objeto, X2, Y2, X3, Y3);
     AgregaCuadro(Cuadros[5].Objeto, X3, Y2, X4, Y3);
     AgregaCuadro(Cuadros[6].Objeto, X1, Y3, X2, Y4);
     AgregaCuadro(Cuadros[7].Objeto, X2, Y3, X3, Y4);
     AgregaCuadro(Cuadros[8].Objeto, X3, Y3, X4, Y4);
    
     Toque := ap_Aplicacion.Entrada.Toca(Control);
     end;
    
     end
     else if Control is if_cObjetoEtiqueta then
     begin
    
     if Boolean(Control.Visible.Valor) then
     begin
     Control.Transformación := gf_Multiplica(Transformación,
     gf_CreaMatriz4x4Traslada(if_cObjetoEtiqueta(Control).X.Valor,
     if_cObjetoEtiqueta(Control).Y.Valor, 0, False));
     Visible := True;
    
     AgregaTrazo;
     AgregaTextura(ImagenFuente);
     if_AlineaTexto(if_cObjetoEtiqueta(Control).Texto.Valor, if_eAlineacion(
     if_cObjetoEtiqueta(Control).Alineacion.Valor), Fuente, XT, YT);
     XT := Trunc(XT);
     YT := Trunc(YT);
     AgregaTexto(if_cObjetoEtiqueta(Control).Texto.Valor, XT, YT);
    
     Toque := ap_Aplicacion.Entrada.Toca(Control);
     end;
    
     end
     else if Control is if_cObjetoBotón then
     begin
    
     if Boolean(Control.Visible.Valor) then
     begin
     if Length(Cuadros) < 9 then
     Exit;
    
     Control.Transformación := gf_Multiplica(Transformación,
     gf_CreaMatriz4x4Traslada(if_cObjetoBoton(Control).X.Valor,
     if_cObjetoBoton(Control).Y.Valor, 0, False));
     Visible := True;
    
     AgregaTrazo;
     AgregaTextura(Imagen);
     oj_cObjeto(Cuadro) := Cuadros[0].Objeto;
     X1 := -BordeIzquierda;
     Y1 := -BordeArriba;
     X2 := X1+Cuadro.Ancho.Valor;
     Y2 := Y1+Cuadro.Alto.Valor;
     oj_cObjeto(Cuadro) := Cuadros[8].Objeto;
     X4 := if_cObjetoPanel(Control).Ancho.Valor+BordeDerecha;
     Y4 := if_cObjetoPanel(Control).Alto.Valor+BordeAbajo;
     X3 := X4-Cuadro.Ancho.Valor;
     Y3 := Y4-Cuadro.Alto.Valor;
     AgregaCuadro(Cuadros[0].Objeto, X1, Y1, X2, Y2);
     AgregaCuadro(Cuadros[1].Objeto, X2, Y1, X3, Y2);
     AgregaCuadro(Cuadros[2].Objeto, X3, Y1, X4, Y2);
     AgregaCuadro(Cuadros[3].Objeto, X1, Y2, X2, Y3);
     AgregaCuadro(Cuadros[4].Objeto, X2, Y2, X3, Y3);
     AgregaCuadro(Cuadros[5].Objeto, X3, Y2, X4, Y3);
     AgregaCuadro(Cuadros[6].Objeto, X1, Y3, X2, Y4);
     AgregaCuadro(Cuadros[7].Objeto, X2, Y3, X3, Y4);
     AgregaCuadro(Cuadros[8].Objeto, X3, Y3, X4, Y4);
    
     AgregaTrazo;
     AgregaTextura(ImagenFuente);
     if_AlineaTexto(if_cObjetoBoton(Control).Texto.Valor,
     if_ALINEACION_CENTRO_MITAD, Fuente, XT, YT);
     XT := Trunc(XT+if_cObjetoBoton(Control).Ancho.Valor/2);
     YT := Trunc(YT+if_cObjetoBoton(Control).Alto.Valor/2);
     AgregaTexto(if_cObjetoBoton(Control).Texto.Valor, XT, YT);
    
     Toque := ap_Aplicacion.Entrada.Toca(Control);
     end;
    
     end
     else if Control is if_cObjetoMarcador then
     begin
    
     if Boolean(Control.Visible.Valor) then
     begin
     if Length(Cuadros) < 1 then
     Exit;
    
     Control.Transformación := gf_Multiplica(Transformación,
     gf_CreaMatriz4x4Traslada(if_cObjetoMarcador(Control).X.Valor,
     if_cObjetoMarcador(Control).Y.Valor, 0, False));
     Visible := True;
    
     AgregaTrazo;
     AgregaTextura(Imagen);
     oj_cObjeto(Cuadro) := Cuadros[0].Objeto;
     X1 := -BordeIzquierda;
     Y1 := -BordeArriba;
     X2 := Cuadro.Ancho.Valor+BordeDerecha;
     Y2 := Cuadro.Alto.Valor+BordeAbajo;
     if_cObjetoMarcador(Control).Ancho.Valor := Cuadro.Ancho.Valor;
     if_cObjetoMarcador(Control).Alto.Valor := Cuadro.Alto.Valor;
     AgregaCuadro(Cuadro, X1, Y1, X2, Y2);
    
     Toque := ap_Aplicacion.Entrada.Toca(Control);
     end;
    
     end
     else if Control is if_cObjetoElección then
     begin
    
     if Boolean(Control.Visible.Valor) then
     begin
     if Length(Cuadros) < 1 then
     Exit;
    
     Control.Transformación := gf_Multiplica(Transformación,
     gf_CreaMatriz4x4Traslada(if_cObjetoEleccion(Control).X.Valor,
     if_cObjetoEleccion(Control).Y.Valor, 0, False));
     Visible := True;
    
     AgregaTrazo;
     AgregaTextura(Imagen);
     oj_cObjeto(Cuadro) := Cuadros[0].Objeto;
     X1 := -BordeIzquierda;
     Y1 := -BordeArriba;
     X2 := Cuadro.Ancho.Valor+BordeDerecha;
     Y2 := Cuadro.Alto.Valor+BordeAbajo;
     if_cObjetoEleccion(Control).Ancho.Valor := Cuadro.Ancho.Valor;
     if_cObjetoEleccion(Control).Alto.Valor := Cuadro.Alto.Valor;
     AgregaCuadro(Cuadro, X1, Y1, X2, Y2);
    
     Toque := ap_Aplicacion.Entrada.Toca(Control);
     end;
    
     end
     else if Control is if_cObjetoMenu then
     begin
    
     if Boolean(Control.Visible.Valor) then
     begin
     if Length(Cuadros) < 15 then
     Exit;
    
     Control.Transformación := gf_Multiplica(Transformación,
     gf_CreaMatriz4x4Traslada(if_cObjetoMenu(Control).X.Valor,
     if_cObjetoMenu(Control).Y.Valor, 0, False));
     Visible := True;
    
     AltoTexto := Fuente.Ascenso.Valor+Fuente.Descenso.Valor;
     AltoOpcion := AltoTexto+Espaciado;
     AnchoTexto := 0;
    
     if Length(if_cObjetoMenu(Control).Opciones.Referencias) > 0 then
     begin
     EOpcion := @if_cObjetoMenu(Control).Opciones.Referencias[0];
     EFinOpcion := @if_cObjetoMenu(Control).Opciones.Referencias[Length(
     if_cObjetoMenu(Control).Opciones.Referencias)];
    
     while EOpcion < EFinOpcion do
     begin
     oj_cObjeto(opción) := EOpcion^.Objeto;
    
     if not (opción is if_cObjetoOpcion) then
     begin
     EOpcion += 1;
     Continue;
     end;
    
     AnchoTexto := cc_Mayor(AnchoTexto, Fuente.MideAnchoTexto(opción.Texto.
     Valor));
     EOpcion += 1;
     end;
    
     end;
    
     if_cObjetoMenu(Control).Ancho.Valor := MargenIzquierda+AnchoTexto+
     MargenDerecha;
     if_cObjetoMenu(Control).Alto.Valor := MargenArriba+AltoOpcion*Length(
     if_cObjetoMenu(Control).Opciones.Referencias)-Espaciado+MargenAbajo;
    
     AgregaTrazo;
     AgregaTextura(Imagen);
     oj_cObjeto(Cuadro) := Cuadros[0].Objeto;
     X1 := -BordeIzquierda;
     Y1 := -BordeArriba;
     X2 := X1+Cuadro.Ancho.Valor;
     Y2 := Y1+Cuadro.Alto.Valor;
     oj_cObjeto(Cuadro) := Cuadros[8].Objeto;
     X4 := if_cObjetoMenu(Control).Ancho.Valor+BordeDerecha;
     Y4 := if_cObjetoMenu(Control).Alto.Valor+BordeAbajo;
     X3 := X4-Cuadro.Ancho.Valor;
     Y3 := Y4-Cuadro.Alto.Valor;
     AgregaCuadro(Cuadros[0].Objeto, X1, Y1, X2, Y2);
     AgregaCuadro(Cuadros[1].Objeto, X2, Y1, X3, Y2);
     AgregaCuadro(Cuadros[2].Objeto, X3, Y1, X4, Y2);
     AgregaCuadro(Cuadros[3].Objeto, X1, Y2, X2, Y3);
     AgregaCuadro(Cuadros[4].Objeto, X2, Y2, X3, Y3);
     AgregaCuadro(Cuadros[5].Objeto, X3, Y2, X4, Y3);
     AgregaCuadro(Cuadros[6].Objeto, X1, Y3, X2, Y4);
     AgregaCuadro(Cuadros[7].Objeto, X2, Y3, X3, Y4);
     AgregaCuadro(Cuadros[8].Objeto, X3, Y3, X4, Y4);
    
     if cc_Dentro(if_cObjetoMenu(Control).IOpcion, Length(if_cObjetoMenu(
     Control).Opciones.Referencias)) = 0 then
     begin
     BordeOpcion := Espaciado/2;
     oj_cObjeto(Cuadro) := Cuadros[9].Objeto;
     X1 := -BordeIzquierda;
     Y1 := MargenArriba+AltoOpcion*if_cObjetoMenu(Control).IOpcion-
     BordeOpcion-BordeArriba;
     X2 := X1+Cuadro.Ancho.Valor;
     Y2 := Y1+AltoTexto+BordeOpcion*2;
     oj_cObjeto(Cuadro) := Cuadros[11].Objeto;
     X4 := if_cObjetoMenu(Control).Ancho.Valor+BordeDerecha;
     X3 := X4-Cuadro.Ancho.Valor;
     AgregaCuadro(Cuadros[9].Objeto, X1, Y1, X2, Y2);
     AgregaCuadro(Cuadros[10].Objeto, X2, Y1, X3, Y2);
     AgregaCuadro(Cuadros[11].Objeto, X3, Y1, X4, Y2);
     end;
    
     oj_cObjeto(Cuadro) := Cuadros[12].Objeto;
     X1 := -BordeIzquierda;
     Y1 := MargenArriba+cc_Centra(Cuadro.Alto.Valor, AltoOpcion)-BordeArriba;
     X2 := X1+Cuadro.Ancho.Valor;
     Y2 := Y1+Cuadro.Alto.Valor;
     oj_cObjeto(Cuadro) := Cuadros[14].Objeto;
     X4 := if_cObjetoMenu(Control).Ancho.Valor+BordeDerecha;
     X3 := X4-Cuadro.Ancho.Valor;
    
     if Length(if_cObjetoMenu(Control).Opciones.Referencias) > 0 then
     begin
     EOpcion := @if_cObjetoMenu(Control).Opciones.Referencias[0];
     EFinOpcion := @if_cObjetoMenu(Control).Opciones.Referencias[Length(
     if_cObjetoMenu(Control).Opciones.Referencias)];
    
     while EOpcion < EFinOpcion do
     begin
     oj_cObjeto(opción) := EOpcion^.Objeto;
    
     if not (opción is if_cObjetoOpcion) then
     begin
     EOpcion += 1;
     Continue;
     end;
    
     if Length(opción.Texto.Valor) <= 0 then
     begin
     AgregaCuadro(Cuadros[12].Objeto, X1, Y1, X2, Y2);
     AgregaCuadro(Cuadros[13].Objeto, X2, Y1, X3, Y2);
     AgregaCuadro(Cuadros[14].Objeto, X3, Y1, X4, Y2);
     end;
    
     Y1 += AltoOpcion;
     Y2 += AltoOpcion;
     EOpcion += 1;
     end;
    
     end;
    
     AgregaTrazo;
     AgregaTextura(ImagenFuente);
    
     XT := MargenIzquierda;
     YT := MargenArriba+Fuente.Ascenso.Valor;
    
     if Length(if_cObjetoMenu(Control).Opciones.Referencias) > 0 then
     begin
     EOpcion := @if_cObjetoMenu(Control).Opciones.Referencias[0];
     EFinOpcion := @if_cObjetoMenu(Control).Opciones.Referencias[Length(
     if_cObjetoMenu(Control).Opciones.Referencias)];
    
     while EOpcion < EFinOpcion do
     begin
     oj_cObjeto(opción) := EOpcion^.Objeto;
    
     if not (opción is if_cObjetoOpcion) then
     begin
     EOpcion += 1;
     Continue;
     end;
    
     AgregaTexto(opción.Texto.Valor, XT, YT);
     YT += AltoOpcion;
     EOpcion += 1;
     end;
    
     end;
    
     Toque := ap_Aplicacion.Entrada.Toca(Control);
     end;
    
     end
     else if Control is if_cObjetoDesplazador then
     begin
    
     if Boolean(Control.Visible.Valor) then
     begin
     if Length(Cuadros) < 9 then
     Exit;
    
     Control.Transformación := gf_Multiplica(Transformación,
     gf_CreaMatriz4x4Traslada(if_cObjetoDesplazador(Control).X.Valor,
     if_cObjetoDesplazador(Control).Y.Valor, 0, False));
     Visible := True;
    
     AgregaTrazo;
     AgregaTextura(Imagen);
     oj_cObjeto(Cuadro) := Cuadros[0].Objeto;
     X1 := -BordeIzquierda;
     Y1 := -BordeArriba;
     X2 := X1+Cuadro.Ancho.Valor;
     Y2 := Y1+Cuadro.Alto.Valor;
     oj_cObjeto(Cuadro) := Cuadros[8].Objeto;
     X4 := if_cObjetoPanel(Control).Ancho.Valor+BordeDerecha;
     Y4 := if_cObjetoPanel(Control).Alto.Valor+BordeAbajo;
     X3 := X4-Cuadro.Ancho.Valor;
     Y3 := Y4-Cuadro.Alto.Valor;
     AgregaCuadro(Cuadros[0].Objeto, X1, Y1, X2, Y2);
     AgregaCuadro(Cuadros[1].Objeto, X2, Y1, X3, Y2);
     AgregaCuadro(Cuadros[2].Objeto, X3, Y1, X4, Y2);
     AgregaCuadro(Cuadros[3].Objeto, X1, Y2, X2, Y3);
     AgregaCuadro(Cuadros[4].Objeto, X2, Y2, X3, Y3);
     AgregaCuadro(Cuadros[5].Objeto, X3, Y2, X4, Y3);
     AgregaCuadro(Cuadros[6].Objeto, X1, Y3, X2, Y4);
     AgregaCuadro(Cuadros[7].Objeto, X2, Y3, X3, Y4);
     AgregaCuadro(Cuadros[8].Objeto, X3, Y3, X4, Y4);
    
     Toque := ap_Aplicacion.Entrada.Toca(Control);
     end;
    
     end
     else if Control is if_cObjetoCampo then
     begin
    
     if Boolean(Control.Visible.Valor) then
     begin
     if Length(Cuadros) < 9 then
     Exit;
    
     Control.Transformación := gf_Multiplica(Transformación,
     gf_CreaMatriz4x4Traslada(if_cObjetoCampo(Control).X.Valor,
     if_cObjetoCampo(Control).Y.Valor, 0, False));
     Visible := True;
    
     AltoTexto := Fuente.Ascenso.Valor+Fuente.Descenso.Valor;
    
     AgregaTrazo;
     AgregaTextura(Imagen);
     oj_cObjeto(Cuadro) := Cuadros[0].Objeto;
     X1 := -BordeIzquierda;
     Y1 := -BordeArriba;
     X2 := X1+Cuadro.Ancho.Valor;
     Y2 := Y1+Cuadro.Alto.Valor;
     oj_cObjeto(Cuadro) := Cuadros[8].Objeto;
     X4 := if_cObjetoPanel(Control).Ancho.Valor+BordeDerecha;
     Y4 := if_cObjetoPanel(Control).Alto.Valor+BordeAbajo;
     X3 := X4-Cuadro.Ancho.Valor;
     Y3 := Y4-Cuadro.Alto.Valor;
     AgregaCuadro(Cuadros[0].Objeto, X1, Y1, X2, Y2);
     AgregaCuadro(Cuadros[1].Objeto, X2, Y1, X3, Y2);
     AgregaCuadro(Cuadros[2].Objeto, X3, Y1, X4, Y2);
     AgregaCuadro(Cuadros[3].Objeto, X1, Y2, X2, Y3);
     AgregaCuadro(Cuadros[4].Objeto, X2, Y2, X3, Y3);
     AgregaCuadro(Cuadros[5].Objeto, X3, Y2, X4, Y3);
     AgregaCuadro(Cuadros[6].Objeto, X1, Y3, X2, Y4);
     AgregaCuadro(Cuadros[7].Objeto, X2, Y3, X3, Y4);
     AgregaCuadro(Cuadros[8].Objeto, X3, Y3, X4, Y4);
    
     AgregaTrazo;
     AgregaTextura(ImagenFuente);
     XT := MargenIzquierda;
     YT := MargenArriba+Fuente.Ascenso.Valor;
     AgregaTexto(if_cObjetoCampo(Control).Texto.Valor, XT, YT);
    
     Toque := ap_Aplicacion.Entrada.Toca(Control);
     end;
    
     end
     else if Control is if_cObjetoHoja then
     begin
    
     if Boolean(Control.Visible.Valor) then
     begin
     if Length(Cuadros) < 9 then
     Exit;
    
     Control.Transformación := gf_Multiplica(Transformación,
     gf_CreaMatriz4x4Traslada(if_cObjetoHoja(Control).X.Valor,
     if_cObjetoHoja(Control).Y.Valor, 0, False));
     Visible := True;
    
     AgregaTrazo;
     AgregaTextura(Imagen);
     oj_cObjeto(Cuadro) := Cuadros[0].Objeto;
     X1 := -BordeIzquierda;
     Y1 := -BordeArriba;
     X2 := X1+Cuadro.Ancho.Valor;
     Y2 := Y1+Cuadro.Alto.Valor;
     oj_cObjeto(Cuadro) := Cuadros[8].Objeto;
     X4 := if_cObjetoPanel(Control).Ancho.Valor+BordeDerecha;
     Y4 := if_cObjetoPanel(Control).Alto.Valor+BordeAbajo;
     X3 := X4-Cuadro.Ancho.Valor;
     Y3 := Y4-Cuadro.Alto.Valor;
     AgregaCuadro(Cuadros[0].Objeto, X1, Y1, X2, Y2);
     AgregaCuadro(Cuadros[1].Objeto, X2, Y1, X3, Y2);
     AgregaCuadro(Cuadros[2].Objeto, X3, Y1, X4, Y2);
     AgregaCuadro(Cuadros[3].Objeto, X1, Y2, X2, Y3);
     AgregaCuadro(Cuadros[4].Objeto, X2, Y2, X3, Y3);
     AgregaCuadro(Cuadros[5].Objeto, X3, Y2, X4, Y3);
     AgregaCuadro(Cuadros[6].Objeto, X1, Y3, X2, Y4);
     AgregaCuadro(Cuadros[7].Objeto, X2, Y3, X3, Y4);
     AgregaCuadro(Cuadros[8].Objeto, X3, Y3, X4, Y4);
    
     Toque := ap_Aplicacion.Entrada.Toca(Control);
     end;
    
     end
     else if Control is if_cObjetoArbol then
     begin
    
     if Boolean(Control.Visible.Valor) then
     begin
     if Length(Cuadros) < 12 then
     Exit;
    
     Control.Transformación := gf_Multiplica(Transformación,
     gf_CreaMatriz4x4Traslada(if_cObjetoArbol(Control).X.Valor,
     if_cObjetoArbol(Control).Y.Valor, 0, False));
     Visible := True;
    
     AltoTexto := Fuente.Ascenso.Valor+Fuente.Descenso.Valor;
     AltoOpcion := AltoTexto+Espaciado;
    
     AgregaTrazo;
     AgregaTextura(Imagen);
     oj_cObjeto(Cuadro) := Cuadros[0].Objeto;
     X1 := -BordeIzquierda;
     Y1 := -BordeArriba;
     X2 := X1+Cuadro.Ancho.Valor;
     Y2 := Y1+Cuadro.Alto.Valor;
     oj_cObjeto(Cuadro) := Cuadros[8].Objeto;
     X4 := if_cObjetoPanel(Control).Ancho.Valor+BordeDerecha;
     Y4 := if_cObjetoPanel(Control).Alto.Valor+BordeAbajo;
     X3 := X4-Cuadro.Ancho.Valor;
     Y3 := Y4-Cuadro.Alto.Valor;
     AgregaCuadro(Cuadros[0].Objeto, X1, Y1, X2, Y2);
     AgregaCuadro(Cuadros[1].Objeto, X2, Y1, X3, Y2);
     AgregaCuadro(Cuadros[2].Objeto, X3, Y1, X4, Y2);
     AgregaCuadro(Cuadros[3].Objeto, X1, Y2, X2, Y3);
     AgregaCuadro(Cuadros[4].Objeto, X2, Y2, X3, Y3);
     AgregaCuadro(Cuadros[5].Objeto, X3, Y2, X4, Y3);
     AgregaCuadro(Cuadros[6].Objeto, X1, Y3, X2, Y4);
     AgregaCuadro(Cuadros[7].Objeto, X2, Y3, X3, Y4);
     AgregaCuadro(Cuadros[8].Objeto, X3, Y3, X4, Y4);
    
     oj_cObjeto(Nodo) := if_cObjetoArbol(Control).Datos.Referencia.Objeto;
    
     if Nodo is dt_cObjetoNodo then
     begin
    
     if Nodo.ISelección >= 0 then
     begin
     BordeOpcion := Espaciado/2;
     oj_cObjeto(Cuadro) := Cuadros[9].Objeto;
     X1 := -BordeIzquierda;
     Y1 := MargenArriba+AltoOpcion*Nodo.ISeleccion-BordeOpcion-BordeArriba;
     X2 := X1+Cuadro.Ancho.Valor;
     Y2 := Y1+AltoTexto+BordeOpcion*2;
     oj_cObjeto(Cuadro) := Cuadros[11].Objeto;
     X4 := if_cObjetoArbol(Control).Ancho.Valor+BordeDerecha;
     X3 := X4-Cuadro.Ancho.Valor;
     AgregaCuadro(Cuadros[9].Objeto, X1, Y1, X2, Y2);
     AgregaCuadro(Cuadros[10].Objeto, X2, Y1, X3, Y2);
     AgregaCuadro(Cuadros[11].Objeto, X3, Y1, X4, Y2);
     end;
    
     AgregaTrazo;
     AgregaTextura(ImagenFuente);
     XT := MargenIzquierda;
     YT := MargenArriba+Fuente.Ascenso.Valor;
     AgregaNodo(Nodo, if_cObjetoArbol(Control).Atributo.Valor, XT, YT,
     if_cObjetoArbol(Control).Ancho.Valor, if_cObjetoArbol(Control).Alto.
     Valor);
     end;
    
     Toque := ap_Aplicacion.Entrada.Toca(Control);
     end;
    
     end
     else if Control is if_cObjetoVisor then
     begin
    
     if Boolean(Control.Visible.Valor) then
     begin
     if Length(Cuadros) < 9 then
     Exit;
    
     Control.Transformación := gf_Multiplica(Transformación,
     gf_CreaMatriz4x4Traslada(if_cObjetoVisor(Control).X.Valor,
     if_cObjetoVisor(Control).Y.Valor, 0, False));
     Visible := True;
    
     AgregaTrazo;
     AgregaTextura(Imagen);
     oj_cObjeto(Cuadro) := Cuadros[0].Objeto;
     X1 := -BordeIzquierda;
     Y1 := -BordeArriba;
     X2 := X1+Cuadro.Ancho.Valor;
     Y2 := Y1+Cuadro.Alto.Valor;
     oj_cObjeto(Cuadro) := Cuadros[8].Objeto;
     X4 := if_cObjetoPanel(Control).Ancho.Valor+BordeDerecha;
     Y4 := if_cObjetoPanel(Control).Alto.Valor+BordeAbajo;
     X3 := X4-Cuadro.Ancho.Valor;
     Y3 := Y4-Cuadro.Alto.Valor;
     AgregaCuadro(Cuadros[0].Objeto, X1, Y1, X2, Y2);
     AgregaCuadro(Cuadros[1].Objeto, X2, Y1, X3, Y2);
     AgregaCuadro(Cuadros[2].Objeto, X3, Y1, X4, Y2);
     AgregaCuadro(Cuadros[3].Objeto, X1, Y2, X2, Y3);
     AgregaCuadro(Cuadros[4].Objeto, X2, Y2, X3, Y3);
     AgregaCuadro(Cuadros[5].Objeto, X3, Y2, X4, Y3);
     AgregaCuadro(Cuadros[6].Objeto, X1, Y3, X2, Y4);
     AgregaCuadro(Cuadros[7].Objeto, X2, Y3, X3, Y4);
     AgregaCuadro(Cuadros[8].Objeto, X3, Y3, X4, Y4);
    
     oj_cObjeto(_Imagen) := if_cObjetoVisor(Control).Imagen.Referencia.Objeto;
    
     if (_Imagen is rc_cObjetoImagen) and (Length(_Imagen.imágenes) > 0) then
     begin
     Imagen := _Imagen.imágenes[0];
     AgregaTrazo;
     AgregaTextura(Imagen);
    
     case if_eVista(if_cObjetoVisor(Control).Vista.Valor) of
     if_VISTA_AREA: gf_AgregaCuadroPlano(X1, Y1, X4-X1, Y4-Y1,
     if_cObjetoVisor(Control).XVista.Valor, if_cObjetoVisor(Control).
     YVista.Valor, if_cObjetoVisor(Control).AnchoVista.Valor,
     if_cObjetoVisor(Control).AltoVista.Valor, Imagen.TomaAncho, Imagen.
     TomaAlto, nil, nil, Trazo.Vertices);
     else
     gf_AgregaCuadroPlano(X1, Y1, X4-X1, Y4-Y1, 0, 0, Imagen.TomaAncho,
     Imagen.TomaAlto, Imagen.TomaAncho, Imagen.TomaAlto, nil, nil, Trazo.
     Vertices);
     end;
    
     end;
    
     Toque := ap_Aplicacion.Entrada.Toca(Control);
     end;
    
     end
     else if Control is if_cObjetoVentana then
     begin
    
     if Boolean(Control.Visible.Valor) then
     begin
     if Length(Cuadros) < 9 then
     Exit;
    
     Control.Transformación := gf_Multiplica(Transformación,
     gf_CreaMatriz4x4Traslada(if_cObjetoVentana(Control).X.Valor,
     if_cObjetoVentana(Control).Y.Valor, 0, False));
     Visible := True;
    
     AgregaTrazo;
     AgregaTextura(Imagen);
     oj_cObjeto(Cuadro) := Cuadros[0].Objeto;
     X1 := -BordeIzquierda;
     Y1 := -BordeArriba;
     X2 := X1+Cuadro.Ancho.Valor;
     Y2 := Y1+Cuadro.Alto.Valor;
     oj_cObjeto(Cuadro) := Cuadros[8].Objeto;
     X4 := if_cObjetoPanel(Control).Ancho.Valor+BordeDerecha;
     Y4 := if_cObjetoPanel(Control).Alto.Valor+BordeAbajo;
     X3 := X4-Cuadro.Ancho.Valor;
     Y3 := Y4-Cuadro.Alto.Valor;
     AgregaCuadro(Cuadros[0].Objeto, X1, Y1, X2, Y2);
     AgregaCuadro(Cuadros[1].Objeto, X2, Y1, X3, Y2);
     AgregaCuadro(Cuadros[2].Objeto, X3, Y1, X4, Y2);
     AgregaCuadro(Cuadros[3].Objeto, X1, Y2, X2, Y3);
     AgregaCuadro(Cuadros[4].Objeto, X2, Y2, X3, Y3);
     AgregaCuadro(Cuadros[5].Objeto, X3, Y2, X4, Y3);
     AgregaCuadro(Cuadros[6].Objeto, X1, Y3, X2, Y4);
     AgregaCuadro(Cuadros[7].Objeto, X2, Y3, X3, Y4);
     AgregaCuadro(Cuadros[8].Objeto, X3, Y3, X4, Y4);
    
     Toque := ap_Aplicacion.Entrada.Toca(Control);
     end;
    
     end;
    
    end;
    
    //------------------------------------------------------------------------------
    { ec_cObjetoEscena }
    //------------------------------------------------------------------------------
    
    //------------------------------------------------------------------------------
    constructor ec_cObjetoEscena.Create;
    begin
     inherited;
    
     Clase := ec_ClaseEscena;
     Fondo := cl_CreaA8R8G8B8(0, $77, $77, $77);
     PintorControl := ec_cPintorControl.Create;
    end;
    
    //------------------------------------------------------------------------------
    destructor ec_cObjetoEscena.Destroy;
    
    var
     Boceto, FinBoceto: ec_pcBoceto;
    
    begin
     PintorControl.Free;
    
     if Length(Bocetos) > 0 then
     begin
     Boceto := @Bocetos[High(Bocetos)];
     FinBoceto := @Bocetos[0];
    
     while Boceto >= FinBoceto do
     begin
     Boceto^.Free;
     Boceto -= 1;
     end;
    
     end;
    
     inherited;
    end;
    
    //------------------------------------------------------------------------------
    procedure ec_cObjetoEscena.Actualiza;
    
    var
     Boceto, FinBoceto: ec_pcBoceto;
     Color: cl_rColor;
     Visible, Toque: Boolean;
     Cursor: if_cObjetoCursor;
    
    //------------------------------------------------------------------------------
     procedure BocetaControl(
     const Control: if_cObjetoControl;
     const Transformación: gf_rMatriz4x4;
     out Visible,
     Toque: Boolean
     );
    
     var
     _Boceto: ec_cBocetoControl;
     IBoceto: LongInt;
    
     begin
     if not (Control is if_cObjetoControl) then
     Exit;
    
     _Boceto := ec_cBocetoControl.Create(PintorControl);
     _Boceto.Boceta(Control, Transformación, Visible, Toque);
    
     IBoceto := Length(Bocetos);
     SetLength(Bocetos, IBoceto+1);
     Bocetos[IBoceto] := _Boceto;
     end;
    
    //------------------------------------------------------------------------------
    // Boceta los controles recursivamente.
     procedure BocetaControles(
     const Controles: oj_cObjetoArreglo;
     const Transformación: gf_rMatriz4x4
     );
    
     var
     EControl, EFinControl: oj_pcEnlace;
     Control: if_cObjetoControl;
     Visible, Toque: Boolean;
     Cursor: if_cObjetoCursor;
    
     begin
     if Length(Controles.Referencias) <= 0 then
     Exit;
    
     EControl := @Controles.Referencias[0];
     EFinControl := @Controles.Referencias[Length(Controles.Referencias)];
    
     while EControl < EFinControl do
     begin
     oj_cObjeto(Control) := EControl^.Objeto;
    
     if not (Control is if_cObjetoControl) or (Control is if_cObjetoCursor)
     then
     begin
     EControl += 1;
     Continue;
     end;
    
     BocetaControl(Control, Transformación, Visible, Toque);
    
     if Toque then
     begin
     Cursor := ap_Aplicacion.Interfase.Cursor;
     Cursor.Tema.Valor := Control.Tema.Valor;
     Cursor.Aspecto.Valor := Control.Cursor.Valor;
     end;
    
     if Visible then
     BocetaControles(Control.Controles, Control.Transformación);
     EControl += 1;
     end;
    
     end;
    
    begin
    // Limpia la pantalla.
    {$IFDEF GRF_DIRECTX}
     ap_Aplicacion.Pantalla.Dispositivo.Clear(0, nil, D3DCLEAR_TARGET or
     D3DCLEAR_ZBUFFER, Fondo.C, 1, 0);
    {$ENDIF}
    {$IFDEF GRF_OPENGL}
     Color := cl_CreaColor(Fondo);
     glClearColor(Color.R, Color.G, Color.B, Color.A);
     glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);
    {$ENDIF}
    
     if Length(Bocetos) > 0 then
     begin
    // Borra los bocetos anteriores.
     Boceto := @Bocetos[High(Bocetos)];
     FinBoceto := @Bocetos[0];
    
     while Boceto >= FinBoceto do
     begin
     Boceto^.Free;
     Boceto -= 1;
     end;
    
     Bocetos := nil;
     end;
    
    // Boceta los controles dejando los superiores al final del arreglo para que se
    // dibujen por encima.
     ap_Aplicacion.Entrada.IniciaToque;
     Cursor := ap_Aplicacion.Interfase.Cursor;
     Cursor.Tema.Valor := ap_Aplicacion.Interfase.TemaFondo.Valor;
     Cursor.Aspecto.Valor := ap_Aplicacion.Interfase.CursorFondo.Valor;
     BocetaControles(ap_Aplicacion.Interfase.Controles, gf_MATRIZ4X4_IDENTIDAD);
     BocetaControl(ap_Aplicacion.Interfase.Cursor, gf_MATRIZ4X4_IDENTIDAD, Visible,
     Toque);
     ap_Aplicacion.Entrada.Controla;
    
     if Length(Bocetos) > 0 then
     begin
    // Pinta los bocetos.
     Boceto := @Bocetos[0];
     FinBoceto := @Bocetos[Length(Bocetos)];
    
     while Boceto < FinBoceto do
     begin
     Boceto^.Pinta;
     Boceto += 1;
     end;
    
     end;
    
    // Muestra la pintura.
    {$IFDEF GRF_DIRECTX}
     ap_Aplicacion.Pantalla.Dispositivo.Present(nil, nil, 0, nil);
    {$ENDIF}
    {$IFDEF GRF_OPENGL}
     ap_Aplicacion.Pantalla.Dispositivo.SwapBuffers;
    {$ENDIF}
    end;
    
    //------------------------------------------------------------------------------
    procedure ec_Inicia;
    begin
     ec_ClaseEscena := 'cScene';
    
     oj_RegistraClaseNatural(ec_ClaseEscena, ec_cObjetoEscena);
    end;
    
    initialization
     ec_Inicia;
    
    end.

  11. #11
    Expulsado
    Fecha de ingreso
    Dec 2010
    Ubicación
    En matrix
    Mensajes
    1,681

    Re: Busco ayuda para desarrollar video juego (diseñadores, modeladores, músicos)

    Joe, me encanta ver eso (me devi ver el código como 3 veces, y aun lo sigo viendo,:D) porque me da más ganas de seguir adelante con la programación para llegar a tu nivel amigo. Tengo varias metas, y entre ellas esta crear un motor gráfico, veo que tu ya llegaste, y me encanta ver como todo es posible !!

    Sinceramente entiendo bien poco, y si no te importa resolverme una cuantas dudas..
    ¿a que te refiers con la clase ec_cBoceto? que es el boceto?
    como se usa el punto y coma, porque no le encuentro lógica, a veces esta después de sentencias y otras no, no lo entiendo...
    que significa el ^ ¿puntero quizás? ¿ y porque aparece antes y a veces después de variables?
    nil equivale a null?
    las funciones que pone gl al principio están echas ya?

    Y bueno no te pregunto más porque podía llenar varias páginas,jaja.
    Sabes de algún manual en español de esto porque más adelante lo voy a necesitar para entender como trabaja.
    Yo aprendo rápido, sobre todo cuando tengo objetivo fijado, y en un principio ver ese código para mi es frustrante, pero si tu puedes, con esfuerzo yo también y esta claro que podre.:D

    Pd: cada vez me gusta más programar viendo este tipo de cosas,:D tío, te has echo un motor !!!

    Edito: si puedes poner otro modulo, me gustaría ver el de colisiones (en concreto esfera a poligono) y si no es mucho pedir me lo explicas? LLevo tiempo queriendo entender y hacer una colisión esfera poligono, los vectores los manejo algo y lo más que llegue es a conseguir detectar una esfera con un poligono y que la esfera se pare, pero no fui capaz de conseguir que la esfera "resbale" por el poligono, y ni te cuento si choca con dos polígonos a la vez, siempre atraviesa uno de ellos.
    (aprovecho que hablo con alguien como tu para preguntar :D)
    Última edición por aprendiz; 19-07-2011 a las 05:45

  12. #12
    Miembro Nuevo
    Fecha de ingreso
    Jul 2011
    Mensajes
    17

    Re: Busco ayuda para desarrollar video juego (diseñadores, modeladores, músicos)

    Bueno, digamos que lo que hice es el fundamento para el motor gráfico. Si se le pone un compilador para un lenguaje de programación, se convertiría en un Blitz multiplataforma. Aún me faltan algunas cosas, como animaciones por huesos, más importadores de archivos 3D, y mejoras en los shaders. Por eso necesito una mano.

    Lo de Boceto es simplemente una clase de la que se deriva cualquier otra clase que represente un objeto en 3D. Luego la clase Pintor se encarga de dibujar los Bocetos. Debido a que este motor utiliza DX y OGL, se requiere crear estas clases intermedías que manejan la geometría de forma genérica.

    Sabía que te iba a gustar Object Pascal. Manejar el punto y coma en Pascal es sencillo, pero tendrías que mirar un manual del lenguaje para aprender a usarlo. Tienes razón con el ^, cuando se pone adelante es para definir tipos punteros, y cuando esta atrás es para referirse al contenido apuntado por el puntero. nil es equivalente a null como dices. Además el símbolo @ se usar para obtener la posición en memoria de una variable.

    Esas funciones con gl adelante son de OpenGL, que vienen listas en las bibliotecas: OpenGLContext, GL, GLU, GLext. Y algunas bibliotecas DirectX son: Direct3D9, D3DX9. Para OGL llamas funciones, y para DX instancias objetos y llamas a sus métodos. Las constantes de DX suelen comenzar con D3D, o cosas así. Para trabajar en estas APIs necesitas tener referencias cerca para consultarlas constantemente. Los identificadores en Pascal y en las referencias suelen ser los mismos, así que no hay forma de perderse.

    Mira las funciones de colisiones son pura geometría, y me refiero a que son complicadas. Te puedo enseñar los fundamentos, pero en este caso es mejor que te consigas un libro sobre el tema. Aquí te dejo un módulo que hice, pero fue para el motor que es el prototipo del que te mostré arriba. Veras la complejidad de la que hablo. Este módulo lo hice en el transcurso de varias semanas, estudiando detenidamente el libro "Real-Time Collision Detection". Y sucede un detalle, que hoy en día las colisiones son aceleradas por hardware. Solo la parte de las colisiones es como desarrollar otro motor, es un gran proyecto, y al final descubriras que es mejor dejarle el trabajo a la aceleradora, como la Aegis physics. No importa que tan buenas sean tus funciones no podrás superar al hardware.

    Este archivo es uno de los gorditos, veamos si este foro lo aguanta

    Código:
    //==============================================================================
    // MUNDANO
    // Motor de Multimedios
    //
    // Copyright (c) 2005-2009 Marco Antonio Alvarado Pérez
    //
    // MChoque.pas (ch_)
    // Detecta colisiones entre gráficos.
    //==============================================================================
    // NOTAS
    //
    // Los algoritmos están basados en el libro:
    // * Real-Time Collision Detection
    //==============================================================================
    
    {$INCLUDE MDefine.inc}
    
    unit MChoque;
    
    interface
    
    //------------------------------------------------------------------------------
    uses
    // Mundano:
     MDepura,
     MArreglo,
     MComun,
     MCalculo,
     MGráfico,
    // Delphi:
    {$IFDEF CMP_DELPHI}
    {$IFDEF PLT_WINDOWS}
     Math;
    {$ENDIF}
    {$ENDIF}
    // Free Pascal Compiler:
    {$IFDEF CMP_FPC}
    {$IFDEF PLT_WINDOWS}
    
    {$ENDIF}
    {$IFDEF PLT_UNIX}
    
    {$ENDIF}
    {$IFDEF PLT_DOS}
    
    {$ENDIF}
    {$ENDIF}
    
    //------------------------------------------------------------------------------
    type
    //..
    // Esferas (bounding spheres)
     ch_rEsfera = record
     C: gr_rVector3D; // Centro
     R: Single; // Radio
     end;
    
    //..
    // Cajas alineadas al eje (axis-aligned bounding boxes, AABB)
    //
    // *------------ *------------ -------------
    // | | | ^ | | ^ |
    // | | | | | | | |
    // | | |<----+---->| | *---->|
    // | | | | | | |
    // | | | v | | |
    // ------------* ------------- -------------
    // CajaEje1 CajaEje2 CajaEje3
    //
     ch_rCajaEje1 = record
     Menor, Mayor: gr_rVector3D; // Punto menor y punto mayor
     end;
    
     ch_rCajaEje2 = record
     Menor: gr_rVector3D; // Punto menor
     D: gr_rVector3D; // Diametro
     end;
    
     ch_rCajaEje3 = record
     C: gr_rVector3D; // Centro
     R: gr_rVector3D; // Radio
     end;
    
    //..
    // Cajas de orientación libre (oriented bounding boxes, OBB)
     ch_arEjesCajaLibre = array [0..2] of gr_rVector3D;
    
     ch_rCajaLibre = record
     C: gr_rVector3D; // Centro
     U: ch_arEjesCajaLibre; // Ejes locales
     R: gr_rVector3D; // Radiós sobre cada eje
     end;
    
    //..
    // Politopos de orientación discreta (discrete-orientation polytopes, k-DOP)
     ch_rPolitopo = record
     Menores, Mayores: ar_adSingle; // Distancias desde el origen sobre los
     // ejes 0 a 3.
     end;
    
    //..
    // Capsulas (sphere-swept volumes, SSV)
     ch_rCapsula = packed record
     A, B: gr_rVector3D; // Inicio y fin del segmento
     R: Single; // Radio
     end;
    
    //..
    // Segmentos
    procedure ch_MasCercaPuntoSegmento(const P1, S1, S2: gr_rVector3D;
     var T: Single; var P: gr_rVector3D);
    function ch_MasCercaSegmentoSegmento(const SA1, SA2, SB1, SB2: gr_rVector3D;
     var S, T: Single; var P1, P2: gr_rVector3D): Single;
    function ch_DistanciaCuadradaPuntoSegmento(const P, S1, S2: gr_rVector3D):
     Single;
    function ch_DistanciaCuadradaSegmentoSegmento(const SA1, SA2, SB1, SB2:
     gr_rVector3D): Single;
    
    //..
    // Planos
    function ch_MasCercaPuntoPlano(const P1: gr_rVector3D; const P2: gr_rPlano3D;
     var P: gr_rVector3D; PlanoNormalizado: Boolean = false): Single;
    function ch_DistanciaPuntoPlano(const P1: gr_rVector3D; const P2: gr_rPlano3D;
     PlanoNormalizado: Boolean = false): Single;
    
    //..
    // Triángulos
    function ch_PuntoEnTriángulo(const P, T1, T2, T3: gr_rVector3D): Boolean;
    procedure ch_MasCercaPuntoTriángulo(const P1, T1, T2, T3: gr_rVector3D;
     var P: gr_rVector3D);
    
    //..
    // Rectángulos
    function ch_MasCercaPuntoRectángulo(const P1: gr_rVector3D; const R:
     gr_rRectánguloAxial3D; var P: gr_rVector3D): Single;
    function ch_DistanciaCuadradaPuntoRectángulo(const P1: gr_rVector3D; const R:
     gr_rRectánguloAxial3D): Single;
    
    //..
    // Tetrahedro
    procedure ch_MasCercaPuntoTetrahedro(const P1, PP1, PP2, PP3, PP4:
     gr_rVector3D; var P: gr_rVector3D);
    
    //..
    // Esferas
    function ch_CreaEsfera(const C: ch_rCajaEje1): ch_rEsfera; overload;
    function ch_CreaEsfera(const E: ch_rEsfera; const P: gr_rVector3D): ch_rEsfera;
     overload;
    function ch_CreaEsferaCajaEje(const Puntos: gr_adrVector3D): ch_rEsfera;
    function ch_CreaEsferaRitter(const Puntos: gr_adrVector3D): ch_rEsfera;
    function ch_CreaEsferaEigen(const Puntos: gr_adrVector3D): ch_rEsfera;
    function ch_CreaEsferaRitterEigen(const Puntos: gr_adrVector3D): ch_rEsfera;
    function ch_CreaEsferaRitterIterativa(const Puntos: gr_adrVector3D):
     ch_rEsfera;
    function ch_EsferaEnPlano(const E: ch_rEsfera; const P: gr_rPlano3D): Boolean;
    
    //..
    // Cajas alineadas al eje (axis-aligned bounding boxes, AABB)
    function ch_CreaCajaEje1: ch_rCajaEje1; overload;
    function ch_CreaCajaEje1(const P: gr_rVector3D): ch_rCajaEje1; overload;
    function ch_CreaCajaEje1(const P1, P2: gr_rVector3D): ch_rCajaEje1; overload;
    function ch_CreaCajaEje3(const C, R: gr_rVector3D): ch_rCajaEje3; overload;
    function ch_Une(const C: ch_rCajaEje1; const P: gr_rVector3D):
     ch_rCajaEje1; overload;
    function ch_Une(const C1, C2: ch_rCajaEje1): ch_rCajaEje1; overload;
    function ch_Expande(const C: ch_rCajaEje1; A: Single): ch_rCajaEje1;
    function ch_Volumen(const C: ch_rCajaEje1): Single;
    function ch_EjeMayor(const C: ch_rCajaEje1): Integer;
    function ch_Transforma(const T: gr_rTransformación; const C: ch_rCajaEje1):
     ch_rCajaEje1; overload;
    function ch_ActualizaCajaEje1(const C: ch_rCajaEje1; const M: gr_rMatriz3x3;
     const T: gr_rVector3D): ch_rCajaEje1; overload;
    function ch_ActualizaCajaEje3(const C: ch_rCajaEje3; const M: gr_rMatriz3x3;
     const T: gr_rVector3D): ch_rCajaEje3; overload;
    procedure ch_PuntosMasSeparadosCajaEje(var Menor, Mayor: Integer; const Puntos:
     gr_adrVector3D);
    procedure ch_MasCercaPuntoCajaEje(const P1: gr_rVector3D; const C:
     ch_rCajaEje1; var P: gr_rVector3D);
    function ch_DistanciaCuadradaPuntoCajaEje(const P1: gr_rVector3D; const C:
     ch_rCajaEje1): Single;
    
    //..
    // Cajas de orientación libre (oriented bounding boxes, OBB)
    function ch_MasCercaPuntoCajaLibre(const P1: gr_rVector3D; const C:
     ch_rCajaLibre; var P: gr_rVector3D): Single;
    function ch_DistanciaCuadradaPuntoCajaLibre(const P1: gr_rVector3D; const C:
     ch_rCajaLibre): Single;
    
    //..
    // Politopos de orientación discreta (discrete-orientation polytopes, k-DOP)
    function ch_CreaPolitopo8: ch_rPolitopo; overload;
    function ch_CreaPolitopo8(const Puntos: gr_adrVector3D): ch_rPolitopo;
     overload;
    
    //..
    // Pruebas de Contenido (C), Intersección (I) y Traslapamiento (T):
    //
    // C
    // u
    // a
    // T T Td de P
    // S S r r re r C A P P o
    // e e i i i i i l C o o l
    // g g a a aP l l E i a l l i
    // P m m L P MP n n nl a í s n L p í i h
    // u e e í R l el g g ga te n f Ce Ci s g te e
    // n n n n a a da u u un e de e aa ab u o o d
    // te t2 te e y n in l2 l lo r r r jd jr l n p r
    // o oD o a o o oo oD o os o o a aa ae a o o o
    // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
    // Punto | | | | | | | |C |C | | | | | | | |C | |T |
    // | | | | | | | | | | | | | | | | | | | |
    // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
    // Segmento | |T | | | | | | | | | | | | | | | | | |
    // 2D | | | | | | | | | | | | | | | | | | | |
    // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
    // Segmento | | | | | |I | | |I |I | |I | |T | | | | |I |
    // | | | | | | | | | | | | | | | | | | | |
    // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
    // Línea | | | | | | | | |I | |I | | | | | | | | |
    // | | | | | | | | | | | | | | | | | | | |
    // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
    // Rayo | | | | | | | | |I | | | |IT|I | | | | | |
    // | | | | | | | | | | | | | | | | | | | |
    // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
    // Plano | | | | | |I | | | | | | | |T | | | | | |
    // | | | | | | | | | | | | | | | | | | | |
    // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
    // Triángulo | | | | | | | | |T | | | | |T | | | | | |
    // | | | | | | | | | | | | | | | | | | | |
    // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
    // Esfera | | | | | |T |T | |T | | | |T |T |T |T |T | | |
    // | | | | | | | | | | | | | | | | | | | |
    // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
    // Caja |C | | | | |T | | | | | | | |T | | | | | |
    // alienada | | | | | | | | | | | | | | | | | | | |
    // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
    // Caja | | | | | |T | | | | | | | | |T | | | | |
    // libre | | | | | | | | | | | | | | | | | | | |
    // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
    // Capsula | | | | | | | | | | | | | | | |T | | | |
    // | | | | | | | | | | | | | | | | | | | |
    // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
    // Politopo | | | | | | | | | | | | | | | | | |T | |
    // | | | | | | | | | | | | | | | | | | | |
    // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
    //
    function ch_ContienePuntoTriángulo2DContraReloj(const P, T1, T2, T3:
     gr_rVector2D): Boolean;
    function ch_ContienePuntoTriángulo2D(const P, T1, T2, T3: gr_rVector2D):
     Boolean;
    function ch_ContienePuntoTriánguloContraReloj(const P: gr_rVector3D; T1, T2,
     T3: gr_rVector3D): Boolean;
    function ch_ContienePuntoPoligono(const P1: gr_rVector3D; const P2:
     gr_rPoligono3D): Boolean;
    function ch_TraslapaPuntoPolihedro(const P: gr_rVector3D; const Planos:
     gr_adrPlano3D; PlanoNormalizado: Boolean = false): Boolean;
    function ch_TraslapaSegmento2DSegmento2D(const SA1, SA2, SB1, SB2:
     gr_rVector2D; var T: Single; var P: gr_rVector2D): Boolean;
    function ch_IntersecaSegmentoPlano(const S1, S2: gr_rVector3D; const P1:
     gr_rPlano3D; var T: Single; var P: gr_rVector3D): Boolean;
    function ch_IntersecaSegmentoTriángulo(const S1, S2, T1, T2, T3: gr_rVector3D;
     var U, V, W, T: Single): Boolean;
    function ch_IntersecaSegmentoTriánguloPlanos(const S1, S2: gr_rVector3D; const
     T1: gr_rTriánguloPlanar3D; var U, V, W, T: Single; var S: gr_rVector3D):
     Boolean;
    function ch_TraslapaSegmentoCajaEje1(const S1, S2: gr_rVector3D; const C:
     ch_rCajaEje1): Boolean;
    function ch_IntersecaSegmentoCilindro(const S1, S2, C1, C2: gr_rVector3D; R:
     Single; var T: Single): Boolean;
    function ch_IntersecaSegmentoPolihedro(const S1, S2: gr_rVector3D; const Planos:
     gr_adrPlano3D; var TPrimero, TUltimo: Single): Boolean;
    function ch_IntersecaLineaTriángulo(const L1, L2, T1, T2, T3: gr_rVector3D; var
     U, V, W: Single): Boolean;
    function ch_IntersecaLineaCuadrilateroContraReloj(const L1, L2, C1, C2, C3, C4:
     gr_rVector3D; var P: gr_rVector3D): Boolean;
    function ch_IntersecaRayoTriángulo(const O, D, T1, T2, T3: gr_rVector3D; var T,
     U, V: Single): Boolean;
    function ch_IntersecaRayoEsfera(const O: gr_rVector3D; const D: gr_rVector3D;
     const E: ch_rEsfera; var T: Single; var P: gr_rVector3D): Boolean;
    function ch_TraslapaRayoEsfera(const O: gr_rVector3D; const D: gr_rVector3D;
     const E: ch_rEsfera): Boolean;
    function ch_IntersecaRayoCajaEje1(const O: gr_rVector3D; const D: gr_rVector3D;
     const C: ch_rCajaEje1; var TMenor: Single; var P: gr_rVector3D): Boolean;
    function ch_IntersecaPlanoPlano(const P1, P2: gr_rPlano3D; var P: gr_rVector3D;
     var D: gr_rVector3D): Boolean;
    function ch_IntersecaPlanoPlanoPlano(const P1, P2, P3: gr_rPlano3D; var P:
     gr_rVector3D): Boolean;
    function ch_TraslapaPlanoCajaEje3(const P: gr_rPlano3D; const C: ch_rCajaEje3):
     Boolean;
    function ch_IntersecaTriánguloTriángulo(const TA1, TA2, TA3, TB1, TB2, TB3:
     gr_rVector3D): Boolean;
    function ch_TraslapaTriánguloCajaEje3(const T1, T2, T3: gr_rVector3D; const C:
     ch_rCajaEje3): Boolean;
    function ch_TraslapaEsferaPlano(const E: ch_rEsfera; const P: gr_rPlano3D):
     Boolean;
    function ch_TraslapaEsferaMedioPlano(const E: ch_rEsfera; const P:
     gr_rPlano3D): Boolean;
    function ch_TraslapaEsferaTriángulo(const E: ch_rEsfera; const T1, T2, T3:
     gr_rVector3D; var P: gr_rVector3D): Boolean;
    function ch_TraslapaEsferaEsfera(const E1, E2: ch_rEsfera): Boolean;
    function ch_TraslapaEsferaCajaEje1(const E: ch_rEsfera; const C: ch_rCajaEje1):
     Boolean; overload;
    function ch_TraslapaEsferaCajaEje1(const E: ch_rEsfera; const C: ch_rCajaEje1;
     var P: gr_rVector3D): Boolean; overload;
    function ch_TraslapaEsferaCajaLibre(const E: ch_rEsfera; const C:
     ch_rCajaLibre; var P: gr_rVector3D): Boolean;
    function ch_TraslapaEsferaCapsula(const E: ch_rEsfera; const C: ch_rCapsula):
     Boolean;
    function ch_TraslapaEsferaPoligono(const E: ch_rEsfera; const P:
     gr_rPoligono3D): Boolean;
    function ch_ContieneCajaEje1Punto(const C: ch_rCajaEje1; const P:
     gr_rVector3D): Boolean;
    function ch_TraslapaCajaEje1Plano(const C: ch_rCajaEje1; const P: gr_rPlano3D):
     Boolean;
    function ch_TraslapaCajaEje1CajaEje1(const C1, C2: ch_rCajaEje1): Boolean;
    function ch_TraslapaCajaEje2CajaEje2(const C1, C2: ch_rCajaEje2): Boolean;
    function ch_TraslapaCajaEje3CajaEje3(const C1, C2: ch_rCajaEje3): Boolean;
    function ch_TraslapaCajaLibrePlano(const C: ch_rCajaLibre; const P:
     gr_rPlano3D): Boolean;
    function ch_TraslapaCajaLibreCajaLibre(const C1, C2: ch_rCajaLibre): Boolean;
    function ch_TraslapaCapsulaCapsula(const C1, C2: ch_rCapsula): Boolean;
    function ch_TraslapaPolitopoPolitopo(const P1, P2: ch_rPolitopo): Boolean;
    
    implementation
    
    //------------------------------------------------------------------------------
    // Segmentos
    //------------------------------------------------------------------------------
    
    //------------------------------------------------------------------------------
    procedure ch_MasCercaPuntoSegmento(
     const P1, // Punto
     S1, S2: gr_rVector3D; // Puntos que limitan el segmento
     var T: Single; // Posición del punto sobre el segmento
     var P: gr_rVector3D // Punto sobre el segmento, más cercano a P1
     );
    
     var
     AB: gr_rVector3D;
    
    begin
     AB := gr_Resta(S2, S1);
     T := gr_ProductoPunto(gr_Resta(P1, S1), AB)/gr_ProductoPunto(AB, AB);
     T := cc_Limita(T, 0, 1);
     P := gr_Suma(S1, gr_Multiplica(AB, T));
    end;
    
    //------------------------------------------------------------------------------
    function ch_MasCercaSegmentoSegmento(
     const SA1, SA2, // Puntos que limitan el segmento A
     SB1, SB2: gr_rVector3D; // Puntos que limitan el segmento B
     var S, T: Single; // Parámetros de los segmentos
     var P1, P2: gr_rVector3D // Puntos más cercanos
     ): Single; // Distancia cuadrada entre S1(S) y S2(T)
    
     var
     D1, D2, R: gr_rVector3D;
     A, E, F, C, B, D: Single;
    
    begin
     D1 := gr_Resta(SA2, SA1);
     D2 := gr_Resta(SB2, SB1);
     R := gr_Resta(SA1, SB1);
     A := gr_ProductoPunto(D1, D1);
     E := gr_ProductoPunto(D2, D2);
     F := gr_ProductoPunto(D2, R);
    
     if (A <= gr_EPSILON) and (E <= gr_EPSILON) then
     begin
     S := 0;
     T := 0;
     P1 := SA1;
     P2 := SB1;
     result := gr_DistanciaCuadrada(P1, P2);
     exit;
     end;
    
     if A <= gr_EPSILON then
     begin
     S := 0;
     T := F/E;
     T := cc_Limita(T, 0, 1);
     end else
     begin
     C := gr_ProductoPunto(D1, R);
    
     if E <= gr_EPSILON then
     begin
     T := 0;
     S := cc_Limita(-C/A, 0, 1);
     end else
     begin
     B := gr_ProductoPunto(D1, D2);
     D := A*E-B*B;
    
     if D <> 0 then
     begin
     S := cc_Limita((B*F-C*E)/D, 0, 1);
     end else
     begin
     S := 0;
     end;
    
     T := (B*S+F)/E;
    
     if T < 0 then
     begin
     T := 0;
     S := cc_Limita(-C/A, 0, 1);
     end else
     if T > 1 then
     begin
     T := 1;
     S := cc_Limita((B-C)/A, 0, 1);
     end;
    
     end;
    
     end;
    
     P1 := gr_Suma(SA1, gr_Multiplica(D1, S));
     P2 := gr_Suma(SB1, gr_Multiplica(D2, T));
     result := gr_DistanciaCuadrada(P1, P2);
    end;
    
    //------------------------------------------------------------------------------
    function ch_DistanciaCuadradaPuntoSegmento(
     const P, // Punto
     S1, S2: gr_rVector3D // Puntos que limitan el segmento
     ): Single;
    
     var
     AB, AC, BC: gr_rVector3D;
     E, F: Single;
    
    begin
     AB := gr_Resta(S2, S1);
     AC := gr_Resta(P, S1);
     BC := gr_Resta(P, S2);
     E := gr_ProductoPunto(AC, AB);
    
     if E <= 0 then
     begin
     result := gr_ProductoPunto(AC, AC);
     exit;
     end;
    
     F := gr_ProductoPunto(AB, AB);
    
     if E >= F then
     begin
     result := gr_ProductoPunto(BC, BC);
     exit;
     end;
    
     result := gr_ProductoPunto(AC, AC)-E*E/F;
    end;
    
    //------------------------------------------------------------------------------
    function ch_DistanciaCuadradaSegmentoSegmento(
     const SA1, SA2, // Puntos que limitan el segmento A
     SB1, SB2: gr_rVector3D // Puntos que limitan el segmento B
     ): Single;
    
     var
     S, T: Single;
     P1, P2: gr_rVector3D;
    
    begin
     result := ch_MasCercaSegmentoSegmento(SA1, SA2, SB1, SB2, S, T, P1, P2);
    end;
    
    //------------------------------------------------------------------------------
    // Planos
    //------------------------------------------------------------------------------
    
    //------------------------------------------------------------------------------
    function ch_MasCercaPuntoPlano(
     const P1: gr_rVector3D;
     const P2: gr_rPlano3D;
     var P: gr_rVector3D; // Punto sobre el plano P2, más cercano a P1
     PlanoNormalizado: Boolean
     ): Single; // Distancia del punto más cercano al plano
    begin
     if PlanoNormalizado then
     result := gr_ProductoPunto(P2.N, P1)-P2.PP else
     result := (gr_ProductoPunto(P2.N, P1)-P2.PP)/gr_ProductoPunto(P2.N, P2.N);
     P := gr_Resta(P1, gr_Multiplica(P2.N, result));
    end;
    
    //------------------------------------------------------------------------------
    function ch_DistanciaPuntoPlano(
     const P1: gr_rVector3D;
     const P2: gr_rPlano3D;
     PlanoNormalizado: Boolean
     ): Single;
    begin
     if PlanoNormalizado then
     result := gr_ProductoPunto(P2.N, P1)-P2.PP else
     result := (gr_ProductoPunto(P2.N, P1)-P2.PP)/gr_ProductoPunto(P2.N, P2.N);
    end;
    
    //------------------------------------------------------------------------------
    // Triángulos
    //------------------------------------------------------------------------------
    
    //------------------------------------------------------------------------------
    function ch_PuntoEnTriángulo(
     const P, // Punto
     T1, T2, T3: gr_rVector3D // Puntos del triángulo
     ): Boolean;
    
     var
     U, V, W: Single;
    
    begin
     gr_Baricentricas(T1, T2, T3, P, U, V, W);
     result := (V >= 0) and (W >= 0) and (V+W <= 1);
    end;
    
    //------------------------------------------------------------------------------
    procedure ch_MasCercaPuntoTriángulo(
     const P1, // Punto
     T1, T2, T3: gr_rVector3D; // Puntos del triángulo
     var P: gr_rVector3D // Punto en el triángulo, más cercano a P1
     );
    
     var
     AB, AC, AP, BP, CP: gr_rVector3D;
     D1, D2, D3, D4, D5, D6, V, W, VA, VB, VC, D: Single;
    
    begin
     AB := gr_Resta(T2, T1);
     AC := gr_Resta(T3, T1);
     AP := gr_Resta(P1, T1);
     D1 := gr_ProductoPunto(AB, AP);
     D2 := gr_ProductoPunto(AC, AP);
    
     if (D1 <= 0) and (D2 <= 0) then
     begin
     P := T1;
     exit;
     end;
    
     BP := gr_Resta(P1, T2);
     D3 := gr_ProductoPunto(AB, BP);
     D4 := gr_ProductoPunto(AC, BP);
    
     if (D3 >= 0) and (D4 <= D3) then
     begin
     P := T2;
     exit;
     end;
    
     VC := D1*D4-D3*D2;
    
     if (VC <= 0) and (D1 >= 0) and (D3 <= 0) then
     begin
     V := D1/(D1-D3);
     P := gr_Suma(T1, gr_Multiplica(AB, V));
     exit;
     end;
    
     CP := gr_Resta(P1, T3);
     D5 := gr_ProductoPunto(AB, CP);
     D6 := gr_ProductoPunto(AC, CP);
    
     if (D6 >= 0) and (D5 <= D6) then
     begin
     P := T3;
     exit;
     end;
    
     VB := D5*D2-D1*D6;
    
     if (VB <= 0) and (D2 >= 0) and (D6 <= 0) then
     begin
     W := D2/(D2-D6);
     P := gr_Suma(T1, gr_Multiplica(AC, W));
     exit;
     end;
    
     VA := D3*D6-D5*D4;
    
     if (VA <= 0) and (D4-D3 >= 0) and (D5-D6 >= 0) then
     begin
     W := (D4-D3)/((D4-D3)+(D5-D6));
     P := gr_Suma(T2, gr_Multiplica(gr_Resta(T3, T2), W));
     exit;
     end;
    
     D := 1/(VA+VB+VC);
     V := VB*D;
     W := VC*D;
     P := gr_Suma(T1, gr_Suma(gr_Multiplica(AB, V), gr_Multiplica(AC, W)));
    end;
    
    //------------------------------------------------------------------------------
    // Rectángulos
    //------------------------------------------------------------------------------
    
    //------------------------------------------------------------------------------
    function ch_MasCercaPuntoRectángulo(
     const P1: gr_rVector3D;
     const R: gr_rRectánguloAxial3D;
     var P: gr_rVector3D
     ): Single;
    
     var
     D: gr_rVector3D;
     I: Integer;
     L: Single;
    
    begin
     D := gr_Resta(P1, R.C);
     P := R.C;
    
     for I := 0 to 2 do
     begin
     L := cc_Limita(gr_ProductoPunto(D, R.U[I]), -R.R.M[I], R.R.M[I]);
     P := gr_Suma(P, gr_Multiplica(R.U[I], L));
     end;
    
     D := gr_Resta(P, P1);
     result := gr_ProductoPunto(D, D);
    end;
    
    //------------------------------------------------------------------------------
    function ch_DistanciaCuadradaPuntoRectángulo(
     const P1: gr_rVector3D;
     const R: gr_rRectánguloAxial3D
     ): Single;
    
     var
     P: gr_rVector3D;
    
    begin
     result := ch_MasCercaPuntoRectángulo(P1, R, P);
    end;
    
    //------------------------------------------------------------------------------
    // Tetrahedro
    //------------------------------------------------------------------------------
    
    //------------------------------------------------------------------------------
    procedure ch_MasCercaPuntoTetrahedro(
     const P1,
     PP1, PP2, PP3, PP4: gr_rVector3D;
     var P: gr_rVector3D
     );
    
     var
     MejorD, D: Single;
     que: gr_rVector3D;
    
    begin
     P := P1;
     MejorD := MaxSingle;
    
     if gr_PuntoFueraPlano(P1, PP1, PP2, PP3) then
     begin
     ch_MasCercaPuntoTriángulo(P1, PP1, PP2, PP3, que);
     D := gr_ProductoPunto(gr_Resta(que, P1), gr_Resta(que, P1));
    
     if D < MejorD then
     begin
     MejorD := D;
     P := que;
     end;
    
     end;
    
     if gr_PuntoFueraPlano(P1, PP1, PP3, PP4) then
     begin
     ch_MasCercaPuntoTriángulo(P1, PP1, PP3, PP4, que);
     D := gr_ProductoPunto(gr_Resta(que, P1), gr_Resta(que, P1));
    
     if D < MejorD then
     begin
     MejorD := D;
     P := que;
     end;
    
     end;
    
     if gr_PuntoFueraPlano(P1, PP1, PP4, PP2) then
     begin
     ch_MasCercaPuntoTriángulo(P1, PP1, PP4, PP2, que);
     D := gr_ProductoPunto(gr_Resta(que, P1), gr_Resta(que, P1));
    
     if D < MejorD then
     begin
     MejorD := D;
     P := que;
     end;
    
     end;
    
     if gr_PuntoFueraPlano(P1, PP2, PP4, PP3) then
     begin
     ch_MasCercaPuntoTriángulo(P1, PP2, PP4, PP3, que);
     D := gr_ProductoPunto(gr_Resta(que, P1), gr_Resta(que, P1));
    
     if D < MejorD then
     begin
    // MejorD := D;
     P := que;
     end;
    
     end;
    
    end;
    
    //------------------------------------------------------------------------------
    // Esferas
    //------------------------------------------------------------------------------
    
    //------------------------------------------------------------------------------
    function ch_CreaEsfera(
     const C: ch_rCajaEje1
     ): ch_rEsfera;
    begin
     result.C := gr_Suma(
     gr_Multiplica(C.Menor, 0.5),
     gr_Multiplica(C.Mayor, 0.5));
     result.R := gr_Distancia(result.C, C.Mayor);
    end;
    
    //------------------------------------------------------------------------------
    function ch_CreaEsfera(
     const E: ch_rEsfera;
     const P: gr_rVector3D
     ): ch_rEsfera;
    
     var
     D2, D, K: Single;
    
    begin
     D2 := gr_DistanciaCuadrada(P, E.C);
    
     if D2 > E.R*E.R then
     begin
     D := Sqrt(D2);
     result.R := (E.R+D)*0.5;
     K := (result.R-E.R)/D;
     result.C := gr_Suma(E.C, D*K);
     end;
    
    end;
    
    //------------------------------------------------------------------------------
    function ch_CreaEsferaCajaEje(
     const Puntos: gr_adrVector3D
     ): ch_rEsfera;
    
     var
     Menor, Mayor: Integer;
    
    begin
     ch_PuntosMasSeparadosCajaEje(Menor, Mayor, Puntos);
     result.C := gr_Multiplica(gr_Suma(Puntos[Menor], Puntos[Mayor]), 0.5);
     result.R := gr_Distancia(Puntos[Mayor], result.C);
    end;
    
    //------------------------------------------------------------------------------
    function ch_CreaEsferaRitter(
     const Puntos: gr_adrVector3D
     ): ch_rEsfera;
    
     var
     IPunto: Integer;
    
    begin
     result := ch_CreaEsferaCajaEje(Puntos);
     for IPunto := 0 to High(Puntos) do
     result := ch_CreaEsfera(result, Puntos[IPunto]);
    end;
    
    //------------------------------------------------------------------------------
    function ch_CreaEsferaEigen(
     const Puntos: gr_adrVector3D
     ): ch_rEsfera;
    
     var
     M, V: gr_rMatriz3x3;
     E: gr_rVector3D;
     CMayor: Integer;
     FMayor, EMayor: Single;
     IMenor, IMayor: Integer;
     PMenor, PMayor: gr_rVector3D;
     D: Single;
    
    begin
     M := gr_CreaMatriz3x3Covariante(Puntos);
     gr_Jacobiano(M, V);
    
     CMayor := 0;
     EMayor := Abs(M.M11);
     FMayor := Abs(M.M22);
     if FMayor > EMayor then CMayor := 1;
     FMayor := Abs(M.M33);
     if FMayor > EMayor then CMayor := 2;
    
     E.X := V.M[0,CMayor];
     E.Y := V.M[1,CMayor];
     E.Z := V.M[2,CMayor];
    
     gr_PuntosExtremosEnDireccion(E, Puntos, IMenor, IMayor);
     PMenor := Puntos[IMenor];
     PMayor := Puntos[IMayor];
    
     D := gr_Distancia(PMayor, PMenor);
     result.R := D*0.5;
     result.C := gr_Multiplica(gr_Suma(PMenor, PMayor), 0.5);
    end;
    
    //------------------------------------------------------------------------------
    function ch_CreaEsferaRitterEigen(
     const Puntos: gr_adrVector3D
     ): ch_rEsfera;
    
     var
     IPunto: Integer;
    
    begin
     result := ch_CreaEsferaEigen(Puntos);
     for IPunto := 0 to High(Puntos) do
     result := ch_CreaEsfera(result, Puntos[IPunto]);
    end;
    
    //------------------------------------------------------------------------------
    function ch_CreaEsferaRitterIterativa(
     const Puntos: gr_adrVector3D
     ): ch_rEsfera;
    
     var
     E: ch_rEsfera;
     I, J, K: Integer;
    
    begin
     result := ch_CreaEsferaRitter(Puntos);
     E := result;
    
     for K := 0 to 7 do
     begin
     E.R := E.R*0.95;
    
     for I := 0 to High(Puntos) do
     begin
     J := Trunc(cc_Aleatorio(I+1, High(Puntos)));
     gr_Intercambia(Puntos[I], Puntos[J]);
     ch_CreaEsfera(E, Puntos[I]);
     end;
    
     if E.R < result.R then result := E;
     end;
    
    end;
    
    //------------------------------------------------------------------------------
    function ch_EsferaEnPlano(
     const E: ch_rEsfera; // Esfera
     const P: gr_rPlano3D // Plano
     ): Boolean;
    begin
     result := gr_ProductoPunto(E.C, P.N)-P.PP < -E.R;
    end;
    
    //------------------------------------------------------------------------------
    // Cajas alineadas al eje (axis-aligned bounding boxes, AABB)
    //------------------------------------------------------------------------------
    
    //------------------------------------------------------------------------------
    function ch_CreaCajaEje1: ch_rCajaEje1;
    begin
     result.Menor := gr_CreaVector3D( Infinity, Infinity, Infinity);
     result.Mayor := gr_CreaVector3D(-Infinity, -Infinity, -Infinity);
    end;
    
    //------------------------------------------------------------------------------
    function ch_CreaCajaEje1(
     const P: gr_rVector3D
     ): ch_rCajaEje1;
    begin
     result.Menor := P;
     result.Mayor := P;
    end;
    
    //------------------------------------------------------------------------------
    function ch_CreaCajaEje1(
     const P1, P2: gr_rVector3D
     ): ch_rCajaEje1;
    begin
     result.Menor := gr_CreaVector3D(
     cc_Menor(P1.X, P2.X),
     cc_Menor(P1.Y, P2.Y),
     cc_Menor(P1.Z, P2.Z));
     result.Mayor := gr_CreaVector3D(
     cc_Mayor(P1.X, P2.X),
     cc_Mayor(P1.Y, P2.Y),
     cc_Mayor(P1.Z, P2.Z));
    end;
    
    //------------------------------------------------------------------------------
    function ch_CreaCajaEje3(
     const C, R: gr_rVector3D
     ): ch_rCajaEje3;
    begin
     result.C := C;
     result.R := R;
    end;
    
    //------------------------------------------------------------------------------
    function ch_Une(
     const C: ch_rCajaEje1;
     const P: gr_rVector3D
     ): ch_rCajaEje1;
    begin
     result.Menor.X := cc_Menor(C.Menor.X, P.X);
     result.Menor.Y := cc_Menor(C.Menor.Y, P.Y);
     result.Menor.Z := cc_Menor(C.Menor.Z, P.Z);
     result.Mayor.X := cc_Mayor(C.Mayor.X, P.X);
     result.Mayor.Y := cc_Mayor(C.Mayor.Y, P.Y);
     result.Mayor.Z := cc_Mayor(C.Mayor.Z, P.Z);
    end;
    
    //------------------------------------------------------------------------------
    function ch_Une(
     const C1, C2: ch_rCajaEje1
     ): ch_rCajaEje1;
    begin
     result.Menor.X := cc_Menor(C1.Menor.X, C2.Menor.X);
     result.Menor.Y := cc_Menor(C1.Menor.Y, C2.Menor.Y);
     result.Menor.Z := cc_Menor(C1.Menor.Z, C2.Menor.Z);
     result.Mayor.X := cc_Mayor(C1.Mayor.X, C2.Mayor.X);
     result.Mayor.Y := cc_Mayor(C1.Mayor.Y, C2.Mayor.Y);
     result.Mayor.Z := cc_Mayor(C1.Mayor.Z, C2.Mayor.Z);
    end;
    
    //------------------------------------------------------------------------------
    function ch_Expande(
     const C: ch_rCajaEje1;
     A: Single
     ): ch_rCajaEje1;
    begin
     result.Menor := gr_Resta(C.Menor, gr_CreaVector3D(A, A, A));
     result.Mayor := gr_Suma(C.Mayor, gr_CreaVector3D(A, A, A));
    end;
    
    //------------------------------------------------------------------------------
    function ch_Volumen(
     const C: ch_rCajaEje1
     ): Single;
    
     var
     D: gr_rVector3D;
    
    begin
     D := gr_Resta(C.Mayor, C.Menor);
     result := D.X*D.Y*D.Z;
    end;
    
    //------------------------------------------------------------------------------
    function ch_EjeMayor(
     const C: ch_rCajaEje1
     ): Integer;
    
     var
     D: gr_rVector3D;
    
    begin
     D := gr_Resta(C.Mayor, C.Menor);
     if (D.X > D.Y) and (D.X > D.Z) then result := gr_EJE_X else
     if (D.Y > D.Z) then result := gr_EJE_Y else
     result := gr_EJE_Z;
    end;
    
    //------------------------------------------------------------------------------
    function ch_Transforma(
     const T: gr_rTransformación;
     const C: ch_rCajaEje1
     ): ch_rCajaEje1;
    begin
     result := ch_CreaCajaEje1(gr_Transforma(gr_CreaVector3D(C.Menor.X, C.Menor.Y,
     C.Menor.Z), T));
     result := ch_Une(result, gr_Transforma(gr_CreaVector3D(C.Mayor.X, C.Menor.Y,
     C.Menor.Z), T));
     result := ch_Une(result, gr_Transforma(gr_CreaVector3D(C.Menor.X, C.Mayor.Y,
     C.Menor.Z), T));
     result := ch_Une(result, gr_Transforma(gr_CreaVector3D(C.Menor.X, C.Menor.Y,
     C.Mayor.Z), T));
     result := ch_Une(result, gr_Transforma(gr_CreaVector3D(C.Menor.X, C.Mayor.Y,
     C.Mayor.Z), T));
     result := ch_Une(result, gr_Transforma(gr_CreaVector3D(C.Mayor.X, C.Mayor.Y,
     C.Menor.Z), T));
     result := ch_Une(result, gr_Transforma(gr_CreaVector3D(C.Mayor.X, C.Menor.Y,
     C.Mayor.Z), T));
     result := ch_Une(result, gr_Transforma(gr_CreaVector3D(C.Mayor.X, C.Mayor.Y,
     C.Mayor.Z), T));
    end;
    
    //------------------------------------------------------------------------------
    function ch_ActualizaCajaEje1(
     const C: ch_rCajaEje1;
     const M: gr_rMatriz3x3;
     const T: gr_rVector3D
     ): ch_rCajaEje1;
    
     var
     I, J: Integer;
     E, F: Single;
    
    begin
    
     for I := 0 to 2 do
     begin
     result.Menor.M[I] := T.M[I];
     result.Mayor.M[I] := T.M[I];
    
     for J := 0 to 2 do
     begin
     E := M.M[I,J]*C.Menor.M[J];
     F := M.M[I,J]*C.Mayor.M[J];
    
     if E < F then
     begin
     result.Menor.M[I] := result.Menor.M[I]+E;
     result.Mayor.M[I] := result.Mayor.M[I]+F;
     end else
     begin
     result.Menor.M[I] := result.Menor.M[I]+F;
     result.Mayor.M[I] := result.Mayor.M[I]+E;
     end;
    
     end;
    
     end;
    
    end;
    
    //------------------------------------------------------------------------------
    function ch_ActualizaCajaEje3(
     const C: ch_rCajaEje3;
     const M: gr_rMatriz3x3;
     const T: gr_rVector3D
     ): ch_rCajaEje3;
    
     var
     I, J: Integer;
    
    begin
    
     for I := 0 to 2 do
     begin
     result.C.M[I] := T.M[I];
     result.R.M[I] := 0;
    
     for J := 0 to 2 do
     begin
     result.C.M[I] := result.C.M[I]+M.M[I,J]*C.C.M[J];
     result.R.M[I] := result.R.M[I]+Abs(M.M[I,J])*C.R.M[J];
     end;
    
     end;
    
    end;
    
    //------------------------------------------------------------------------------
    procedure ch_PuntosMasSeparadosCajaEje(
     var Menor, Mayor: Integer;
     const Puntos: gr_adrVector3D
     );
    
     var
     MenorX, MayorX,
     MenorY, MayorY,
     MenorZ, MayorZ: Integer;
     IPunto: Integer;
     D2X, D2Y, D2Z: Single;
    
    begin
     MenorX := 0;
     MayorX := 0;
     MenorY := 0;
     MayorY := 0;
     MenorZ := 0;
     MayorZ := 0;
    
     for IPunto := 0 to High(Puntos) do
     begin
     if Puntos[IPunto].X < Puntos[MenorX].X then MenorX := IPunto;
     if Puntos[IPunto].X > Puntos[MayorX].X then MayorX := IPunto;
     if Puntos[IPunto].Y < Puntos[MenorY].Y then MenorY := IPunto;
     if Puntos[IPunto].Y > Puntos[MayorY].Y then MayorY := IPunto;
     if Puntos[IPunto].Z < Puntos[MenorZ].Z then MenorZ := IPunto;
     if Puntos[IPunto].Z > Puntos[MayorZ].Z then MayorZ := IPunto;
     end;
    
     D2X := gr_DistanciaCuadrada(Puntos[MenorX], Puntos[MayorX]);
     D2Y := gr_DistanciaCuadrada(Puntos[MenorY], Puntos[MayorY]);
     D2Z := gr_DistanciaCuadrada(Puntos[MenorZ], Puntos[MayorZ]);
    
     Menor := MenorX;
     Mayor := MayorX;
    
     if (D2Y > D2X) and (D2Y > D2Z) then
     begin
     Menor := MenorY;
     Mayor := MayorY;
     end else
     if (D2Z > D2X) and (D2Z > D2Y) then
     begin
     Menor := MenorZ;
     Mayor := MayorZ;
     end;
    
    end;
    
    //------------------------------------------------------------------------------
    procedure ch_MasCercaPuntoCajaEje(
     const P1: gr_rVector3D;
     const C: ch_rCajaEje1;
     var P: gr_rVector3D
     );
    
     var
     I: Integer;
     Menor, Mayor: Single;
    
    begin
    
     for I := 0 to 2 do
     begin
     Menor := C.Menor.M[I];
     Mayor := C.Mayor.M[I];
     P.M[I] := cc_Limita(P1.M[I], Menor, Mayor);
     end;
    
    end;
    
    //------------------------------------------------------------------------------
    function ch_DistanciaCuadradaPuntoCajaEje(
     const P1: gr_rVector3D;
     const C: ch_rCajaEje1
     ): Single;
    
     var
     I: Integer;
     Menor, Mayor: Single;
    
    begin
     result := 0;
    
     for I := 0 to 2 do
     begin
     Menor := C.Menor.M[I];
     Mayor := C.Mayor.M[I];
     if Menor > Mayor then cm_Intercambia(Menor, Mayor);
     if P1.M[I] < Menor then result := result+(Menor-P1.M[I])*(Menor-P1.M[I]);
     if P1.M[I] > Mayor then result := result+(P1.M[I]-Mayor)*(P1.M[I]-Mayor);
     end;
    
    end;
    
    //------------------------------------------------------------------------------
    // Cajas de orientación libre (oriented bounding boxes, OBB)
    //------------------------------------------------------------------------------
    
    //------------------------------------------------------------------------------
    function ch_MasCercaPuntoCajaLibre(
     const P1: gr_rVector3D;
     const C: ch_rCajaLibre;
     var P: gr_rVector3D
     ): Single;
    
     var
     D: gr_rVector3D;
     I: Integer;
     L: Single;
    
    begin
     D := gr_Resta(P1, C.C);
     P := C.C;
    
     for I := 0 to 2 do
     begin
     L := cc_Limita(gr_ProductoPunto(D, C.U[I]), -C.R.M[I], C.R.M[I]);
     P := gr_Suma(P, gr_Multiplica(C.U[I], L));
     end;
    
     D := gr_Resta(P, P1);
     result := gr_ProductoPunto(D, D);
    end;
    
    //------------------------------------------------------------------------------
    function ch_DistanciaCuadradaPuntoCajaLibre(
     const P1: gr_rVector3D;
     const C: ch_rCajaLibre
     ): Single;
    
     var
     P: gr_rVector3D;
    
    begin
     result := ch_MasCercaPuntoCajaLibre(P1, C, P);
    end;
    
    //------------------------------------------------------------------------------
    // Politopos de orientación discreta (discrete-orientation polytopes, k-DOP)
    //------------------------------------------------------------------------------
    
    //------------------------------------------------------------------------------
    function ch_CreaPolitopo8: ch_rPolitopo;
    
     var
     I: Integer;
    
    begin
     SetLength(result.Menores, 8);
     SetLength(result.Mayores, 8);
    
     for I := 0 to High(result.Menores) do
     begin
     result.Menores[I] := MaxSingle;
     result.Mayores[I] := -MaxSingle;
     end;
    
    end;
    
    //------------------------------------------------------------------------------
    function ch_CreaPolitopo8(
     const Puntos: gr_adrVector3D
     ): ch_rPolitopo;
    
     var
     V: Single;
     I: Integer;
    
    begin
     result := ch_CreaPolitopo8;
    
     for I := 0 to High(Puntos) do
     begin
     V := +Puntos[I].X+Puntos[I].Y+Puntos[I].Z;
     if V < result.Menores[0] then result.Menores[0] := V else
     if V > result.Mayores[0] then result.Mayores[0] := V;
    
     V := +Puntos[I].X+Puntos[I].Y-Puntos[I].Z;
     if V < result.Menores[1] then result.Menores[1] := V else
     if V > result.Mayores[1] then result.Mayores[1] := V;
    
     V := +Puntos[I].X-Puntos[I].Y+Puntos[I].Z;
     if V < result.Menores[2] then result.Menores[2] := V else
     if V > result.Mayores[2] then result.Mayores[2] := V;
    
     V := -Puntos[I].X+Puntos[I].Y+Puntos[I].Z;
     if V < result.Menores[3] then result.Menores[3] := V else
     if V > result.Mayores[3] then result.Mayores[3] := V;
     end;
    
    end;
    
    //------------------------------------------------------------------------------
    function ch_ContienePuntoTriángulo2DContraReloj(
     const P,
     T1, T2, T3: gr_rVector2D // Puntos del triángulo
     ): Boolean;
    begin
     result := false;
     if gr_ProductoCruz(gr_Resta(P, T1), gr_Resta(T2, T1)) < 0 then exit;
     if gr_ProductoCruz(gr_Resta(P, T2), gr_Resta(T3, T2)) < 0 then exit;
     if gr_ProductoCruz(gr_Resta(P, T3), gr_Resta(T1, T3)) < 0 then exit;
     result := true;
    end;
    
    //------------------------------------------------------------------------------
    function ch_ContienePuntoTriángulo2D(
     const P,
     T1, T2, T3: gr_rVector2D // Puntos del triángulo
     ): Boolean;
    
     var
     PAB, PBC, PCA: Single;
    
    begin
     result := false;
     PAB := gr_ProductoCruz(gr_Resta(P, T1), gr_Resta(T2, T1));
     PBC := gr_ProductoCruz(gr_Resta(P, T2), gr_Resta(T3, T2));
     if Sign(PAB) <> Sign(PBC) then exit;
     PCA := gr_ProductoCruz(gr_Resta(P, T3), gr_Resta(T1, T3));
     if Sign(PAB) <> Sign(PCA) then exit;
     result := true;
    end;
    
    //------------------------------------------------------------------------------
    function ch_ContienePuntoTriánguloContraReloj(
     const P: gr_rVector3D;
     T1, T2, T3: gr_rVector3D // Puntos del triángulo
     ): Boolean;
    
     var
     AB, AC, BC, CC, BB: Single;
    
    begin
     result := false;
    
     T1 := gr_Resta(T1, P);
     T2 := gr_Resta(T2, P);
     T3 := gr_Resta(T3, P);
    
     AB := gr_ProductoPunto(T1, T2);
     AC := gr_ProductoPunto(T1, T3);
     BC := gr_ProductoPunto(T2, T3);
     CC := gr_ProductoPunto(T3, T3);
    
     if BC*AC-CC*AB < 0 then exit;
     BB := gr_ProductoPunto(T2, T2);
     if AB*BC-AC*BB < 0 then exit;
    
     result := true;
    end;
    
    //------------------------------------------------------------------------------
    function ch_ContienePuntoPoligono(
     const P1: gr_rVector3D;
     const P2: gr_rPoligono3D
     ): Boolean;
    
     var
     Menor, Mayor, Medio: Integer;
    
    begin
     result := false;
     Menor := 0;
     Mayor := Length(P2.V);
    
     repeat
     Medio := (Menor+Mayor) shr 1;
     if gr_TriánguloContraReloj(P2.V[0], P2.V[Medio], P1) then
     Menor := Medio else
     Mayor := Medio;
     until Menor+1 >= Mayor;
    
     if (Menor = 0) or (Mayor = Length(P2.V)) then exit;
     result := gr_TriánguloContraReloj(P2.V[Menor], P2.V[Mayor], P1);
    end;
    
    //------------------------------------------------------------------------------
    function ch_TraslapaPuntoPolihedro(
     const P: gr_rVector3D;
     const Planos: gr_adrPlano3D; // Polihedro
     PlanoNormalizado: Boolean
     ): Boolean;
    
     var
     I: Integer;
    
    begin
     result := false;
    
     for I := 0 to High(Planos) do
     begin
     if ch_DistanciaPuntoPlano(P, Planos[I], PlanoNormalizado) > 0 then exit;
     end;
    
     result := true;
    end;
    
    //------------------------------------------------------------------------------
    function ch_TraslapaSegmento2DSegmento2D(
     const SA1, SA2, // Puntos que limitan el segmento A
     SB1, SB2: gr_rVector2D; // Puntos que limitan el segmento B
     var T: Single; // Valor de intersección sobre el segmento A
     var P: gr_rVector2D // Punto de intersección
     ): Boolean;
    
     var
     A1, A2, A3, A4: Single;
    
    begin
     result := false;
     A1 := gr_AreaTriánguloConSigno(SA1, SA2, SB2);
     A2 := gr_AreaTriánguloConSigno(SA1, SA2, SB1);
    
     if A1*A2 < 0 then
     begin
     A3 := gr_AreaTriánguloConSigno(SB1, SB2, SA1);
     A4 := A3+A2-A1;
    
     if A3*A4 < 0 then
     begin
     T := A3/(A3-A4);
     P := gr_Suma(SA1, gr_Multiplica(gr_Resta(SA2, SA1), T));
     result := true;
     end;
    
     end;
    
    end;
    
    //------------------------------------------------------------------------------
    // Basado en:
    // Real-Time Collision Detection, p. 460 (p. 176 no maneja división entre 0).
    function ch_IntersecaSegmentoPlano(
     const S1, S2: gr_rVector3D; // Puntos del segmento
     const P1: gr_rPlano3D;
     var T: Single;
     var P: gr_rVector3D
     ): Boolean;
    
     var
     AB: gr_rVector3D;
     TN, TD, K: Int64;
     V: gr_rVector3D;
    
    begin
     result := false;
    
    { versión de la página 176:
     result := true;
     AB := gr_Resta(S2, S1);
     T := (P1.PP-gr_ProductoPunto(P1.N, S1))/gr_ProductoPunto(P1.N, AB);
    
     if (T >= 0) and (T <= 1) then
     begin
     P := gr_Suma(S1, gr_Multiplica(AB, T));
     exit;
     end;
    
     result := false;
    }
     AB := gr_Resta(S2, S1);
     TN := Trunc(P1.PP-gr_ProductoPunto(P1.N, S1));
     TD := Trunc(gr_ProductoPunto(P1.N, AB));
    
     if TD = 0 then exit;
    
     if TD < 0 then
     begin
     TN := -TN;
     TD := -TD;
     end;
    
     if (TN < 0) or (TN > TD) then exit;
    
     V := gr_CreaVector3D;
     K := TD-1;
    
     if TD > 0 then K := -K;
     if P1.N.X > 0 then V.X := +K else
     if P1.N.X < 0 then V.X := -K;
     if P1.N.Y > 0 then V.Y := +K else
     if P1.N.Y < 0 then V.Y := -K;
     if P1.N.Z > 0 then V.Z := +K else
     if P1.N.Z < 0 then V.Z := -K;
    
     P := gr_Suma(S1, gr_Divide(gr_Suma(gr_Multiplica(AB, TN), V), TD));
     result := true; 
    end;
    
    //------------------------------------------------------------------------------
    function ch_IntersecaSegmentoTriángulo(
     const S1, S2, // Puntos del segmento
     T1, T2, T3: gr_rVector3D; // Puntos del triángulo
     var U, V, W, // Coordenadas baricéntricas
     T: Single
     ): Boolean;
    
     var
     AB, AC, QP, AP, E, N: gr_rVector3D;
     D, ID: Single;
    
    begin
     result := false;
     AB := gr_Resta(T2, T1);
     AC := gr_Resta(T3, T1);
     QP := gr_Resta(S1, S2);
    
     N := gr_ProductoCruz(AB, AC);
    
     D := gr_ProductoPunto(QP, N);
     if D <= 0 then exit;
    
     AP := gr_Resta(S1, T1);
     T := gr_ProductoPunto(AP, N);
     if T < 0 then exit;
     if T > D then exit;
    
     E := gr_ProductoCruz(QP, AP);
     V := gr_ProductoPunto(AC, E);
     if (V < 0) or (V > D) then exit;
     W := -gr_ProductoPunto(AB, E);
     if (W < 0) or (V+W > D) then exit;
    
     ID := 1/D;
     T := T+ID;
     V := V+ID;
     W := W+ID;
     U := 1-V-W;
     result := true;
    end;
    
    //------------------------------------------------------------------------------
    function ch_IntersecaSegmentoTriánguloPlanos(
     const S1, S2: gr_rVector3D; // Puntos del segmento
     const T1: gr_rTriánguloPlanar3D;
     var U, V, W, // Coordenadas baricéntricas
     T: Single;
     var S: gr_rVector3D // Punto de intersección
     ): Boolean;
    
     var
     DP, DQ, D: Single;
    
    begin
     result := false;
     DP := gr_ProductoPunto(S1, T1.P.N)-T1.P.PP;
     if DP < 0 then exit;
    
     DQ := gr_ProductoPunto(S2, T1.P.N)-T1.P.PP;
     if DQ >= 0 then exit;
    
     D := DP-DQ;
     T := DP/D;
     S := gr_Suma(S1, gr_Multiplica(gr_Resta(S2, S1), T));
    
     U := gr_ProductoPunto(S, T1.BordeBC.N)-T1.BordeBC.PP;
     if (U < 0) or (U > 1) then exit;
    
     V := gr_ProductoPunto(S, T1.BordeCA.N)-T1.BordeCA.PP;
     if V < 0 then exit;
    
     W := 1-U-V;
     if W < 0 then exit;
    
     result := true;
    end;
    
    //------------------------------------------------------------------------------
    function ch_TraslapaSegmentoCajaEje1(
     const S1, S2: gr_rVector3D; // Puntos del segmento
     const C: ch_rCajaEje1
     ): Boolean;
    
     var
     C1, M: gr_rVector3D;
     E, D: gr_rVector3D;
     ADX, ADY, ADZ: Single;
    
    begin
     result := false;
     C1 := gr_Multiplica(gr_Suma(C.Menor, C.Mayor), 0.5);
     E := gr_Resta(C.Mayor, C1);
     M := gr_Multiplica(gr_Suma(S1, S2), 0.5);
     D := gr_Resta(S2, M);
     M := gr_Resta(M, C1);
    
     ADX := Abs(D.X);
     if Abs(M.X) > E.X+ADX then exit;
     ADY := Abs(D.Y);
     if Abs(M.Y) > E.Y+ADY then exit;
     ADZ := Abs(D.Z);
     if Abs(M.Z) > E.Z+ADZ then exit;
    
     ADX := ADX+gr_EPSILON;
     ADY := ADY+gr_EPSILON;
     ADZ := ADZ+gr_EPSILON;
    
     if Abs(M.Y*D.Z-M.Z*D.Y) > E.Y*ADZ+E.Z*ADY then exit;
     if Abs(M.Z*D.X-M.X*D.Z) > E.X*ADZ+E.Z*ADX then exit;
     if Abs(M.X*D.Y-M.Y*D.X) > E.X*ADY+E.Y*ADX then exit;
    
     result := true;
    end;
    
    //------------------------------------------------------------------------------
    function ch_IntersecaSegmentoCilindro(
     const S1, S2, // Puntos del segmento
     C1, C2: gr_rVector3D; // Puntos del cilíndro
     R: Single; // Radio del cilíndro
     var T: Single
     ): Boolean;
    
     var
     D, M, N: gr_rVector3D;
     MD, ND, DD, NN, MN, A, K, C, B, Discr: Single;
    
    begin
     result := false;
     D := gr_Resta(C2, C1);
     M := gr_Resta(S1, C1);
     N := gr_Resta(S2, S1);
     MD := gr_ProductoPunto(M, D);
     ND := gr_ProductoPunto(N, D);
     DD := gr_ProductoPunto(D, D);
    
     if (MD < 0) and (MD+ND < 0) then exit;
     if (MD > DD) and (MD+ND > DD) then exit;
     NN := gr_ProductoPunto(N, N);
     MN := gr_ProductoPunto(M, N);
     A := DD*NN-ND*ND;
     K := gr_ProductoPunto(M, M)-R*R;
     C := DD*K-MD*MD;
    
     if Abs(A) < gr_EPSILON then
     begin
     if C > 0 then exit;
     if MD < 0 then T := -MN/NN else
     if MD > DD then T := (ND-MN)/NN else
     T := 0;
     result := true;
     exit;
     end;
    
     B := DD*MN-ND*MD;
     Discr := B*B-A*C;
     if Discr < 0 then exit;
    
     T := (-B-Sqrt(Discr))/A;
     if (T < 0) or (T > 1) then exit;
    
     if MD+T*ND < 0 then
     begin
     if ND <= 0 then exit;
     T := -MD/ND;
     result := K+2*T*(MN+T*NN) <= 0;
     exit;
     end else
     if MD+T*ND > DD then
     begin
     if ND >= 0 then exit;
     T := (DD-MD)/ND;
     result := K+DD-2*MD+T*(2*(MN-ND)+T*NN) <= 0;
     exit;
     end;
    
     result := true;
    end;
    
    //------------------------------------------------------------------------------
    function ch_IntersecaSegmentoPolihedro(
     const S1, S2: gr_rVector3D; // Puntos del segmento
     const Planos: gr_adrPlano3D; // Planos del polihedro
     var TPrimero, TUltimo: Single
     ): Boolean;
    
     var
     D: gr_rVector3D;
     I: Integer;
     Denom, Dist, T: Single;
    
    begin
     result := false;
     D := gr_Resta(S2, S1);
     TPrimero := 0;
     TUltimo := 0;
    
     for I := 0 to High(Planos) do
     begin
     Denom := gr_ProductoPunto(Planos[I].N, D);
     Dist := Planos[I].PP-gr_ProductoPunto(Planos[I].N, S1);
    
     if Denom = 0 then
     begin
     if Dist > 0 then exit;
     end else
     begin
     T := Dist/Denom;
    
     if Denom < 0 then
     begin
     if T > TPrimero then TPrimero := T;
     end else
     begin
     if T < TUltimo then TUltimo := T;
     end;
    
     if TPrimero > TUltimo then exit;
     end;
    
     end;
    
     result := true;
    end;
    
    //------------------------------------------------------------------------------
    function ch_IntersecaLineaTriángulo(
     const L1, L2, // Puntos sobre la línea
     T1, T2, T3: gr_rVector3D; // Puntos del triángulo
     var U, V, W: Single // Coordenadas baricéntricas de intersección
     ): Boolean;
    
     var
     PQ, PA, PB, PC: gr_rVector3D;
     D: Single;
    
    begin
     result := false;
     PQ := gr_Resta(L2, L1);
     PA := gr_Resta(T1, L1);
     PB := gr_Resta(T2, L1);
     PC := gr_Resta(T3, L1);
    
     U := gr_ProductoTripleEscalar(PQ, PC, PB);
     if U < 0 then exit;
     V := gr_ProductoTripleEscalar(PQ, PA, PC);
     if V < 0 then exit;
     W := gr_ProductoTripleEscalar(PQ, PB, PA);
     if W < 0 then exit;
    
     D := 1/(U+V+W);
     U := U*D;
     V := V*D;
     W := W*D;
     result := true;
    end;
    
    //------------------------------------------------------------------------------
    function ch_IntersecaLineaCuadrilateroContraReloj(
     const L1, L2, // Puntos de la línea
     C1, C2, C3, C4: gr_rVector3D; // Puntos del cuadrilatero contra reloj
     var P: gr_rVector3D // Punto de intersección
     ): Boolean;
    
     var
     PQ, PA, PB, PC, PD, M: gr_rVector3D;
     U, V, W, Denom: Single;
    
    begin
     result := false;
     PQ := gr_Resta(L2, L1);
     PA := gr_Resta(C1, L1);
     PB := gr_Resta(C2, L1);
     PC := gr_Resta(C3, L1);
    
     M := gr_ProductoCruz(PC, PQ);
     V := gr_ProductoPunto(PA, M);
    
     if V >= 0 then
     begin
     U := -gr_ProductoPunto(PB, M);
     if U < 0 then exit;
     W := gr_ProductoTripleEscalar(PQ, PB, PA);
     if W < 0 then exit;
     Denom := 1/(U+V+W);
     U := U*Denom;
     V := V*Denom;
     W := W*Denom;
     P := gr_Suma(gr_Suma(gr_Multiplica(C1, U), gr_Multiplica(C2, V)),
     gr_Multiplica(C3, W));
     end else
     begin
     PD := gr_Resta(C4, L1);
     U := gr_ProductoPunto(PD, M);
     if U < 0 then exit;
     W := gr_ProductoTripleEscalar(PQ, PA, PD);
     if W < 0 then exit;
     V := -V;
     Denom := 1/(U+V+W);
     U := U*Denom;
     V := V*Denom;
     W := W*Denom;
     P := gr_Suma(gr_Suma(gr_Multiplica(C1, U), gr_Multiplica(C4, V)),
     gr_Multiplica(C3, W));
     end;
    
     result := true;
    end;
    
    //------------------------------------------------------------------------------
    // Basado en:
    // http://www.cs.lth.se/home/Tomas_Akenine_Moller/raytri/
    function ch_IntersecaRayoTriángulo(
     const O, // Origen del rayo
     D, // Dirección del rayo
    	T1, T2, T3: gr_rVector3D; // Puntos del triángulo
     var T, // Distancia del origen del rayo al punto de
     // intersección
     U, V: Single // Coordenadas baricéntricas
     ): Boolean;
    
     var
     B1, B2, TV, PV, QV: gr_rVector3D;
     D1, ID1: Single;
    
    begin
     result := false;
     B1 := gr_Resta(T2, T1);
     B2 := gr_Resta(T3, T1);
     PV := gr_ProductoCruz(D, B2);
     D1 := gr_ProductoPunto(B1, PV);
    
     if D1 > gr_EPSILON then
     begin
     TV := gr_Resta(O, T1);
     U := gr_ProductoPunto(TV, PV);
     if (U < 0) or (U > D1) then exit;
    
     QV := gr_ProductoCruz(TV, B1);
     V := gr_ProductoPunto(D, QV);
     if (V < 0) or (U+V > D1) then exit;
     end else
     if D1 < -gr_EPSILON then
     begin
     TV := gr_Resta(O, T1);
     U := gr_ProductoPunto(TV, PV);
     if (U > 0) or (U < D1) then exit;
    
     QV := gr_ProductoCruz(TV, B1);
     V := gr_ProductoPunto(D, QV);
     if (V > 0) or (U+V < D1) then exit;
     end else
     begin
     exit;
     end;
    
     ID1 := 1/D1;
    
     T := gr_ProductoPunto(B2, QV)*ID1;
     U := U*ID1;
     V := V*ID1;
     result := true;
    end;
    
    //------------------------------------------------------------------------------
    function ch_IntersecaRayoEsfera(
     const O: gr_rVector3D; // Origen del rayo
     const D: gr_rVector3D; // Dirección del rayo
     const E: ch_rEsfera;
     var T: Single;
     var P: gr_rVector3D // Punto de intersección
     ): Boolean;
    
     var
     M: gr_rVector3D;
     B, C, DS: Single;
    
    begin
     result := false;
     M := gr_Resta(O, E.C);
     B := gr_ProductoPunto(M, D);
     C := gr_ProductoPunto(M, M)-E.R*E.R;
     if (C > 0) and (B > 0) then exit;
    
     DS := B*B-C;
     if DS < 0 then exit;
    
     T := -B-Sqrt(DS);
     if T < 0 then T := 0;
     P := gr_Suma(O, gr_Multiplica(D, T));
     result := true;
    end;
    
    //------------------------------------------------------------------------------
    function ch_TraslapaRayoEsfera(
     const O: gr_rVector3D; // Origen del rayo
     const D: gr_rVector3D; // Dirección del rayo
     const E: ch_rEsfera
     ): Boolean;
    
     var
     M: gr_rVector3D;
     B, C, DS: Single;
    
    begin
     result := true;
     M := gr_Resta(O, E.C);
     C := gr_ProductoPunto(M, M)-E.R*E.R;
     if C <= 0 then exit;
    
     result := false;
     B := gr_ProductoPunto(M, D);
     if B > 0 then exit;
    
     DS := B*B-C;
     if DS < 0 then exit;
    
     result := true;
    end;
    
    //------------------------------------------------------------------------------
    function ch_IntersecaRayoCajaEje1(
     const O: gr_rVector3D;
     const D: gr_rVector3D;
     const C: ch_rCajaEje1;
     var TMenor: Single;
     var P: gr_rVector3D
     ): Boolean;
    
     var
     TMayor, ID, T1, T2: Single;
     I: Integer;
    
    begin
     result := false;
     TMenor := 0;
     TMayor := MaxSingle;
    
     for I := 0 to 2 do
     begin
    
     if Abs(D.M[I]) < gr_EPSILON then
     begin
     if (O.M[I] < C.Menor.M[I]) or (P.M[I] > C.Mayor.M[I]) then exit;
     end else
     begin
     ID := 1/D.M[I];
     T1 := (C.Menor.M[I]-O.M[I])*ID;
     T2 := (C.Mayor.M[I]-O.M[I])*ID;
     if T1 > T2 then cm_Intercambia(T1, T2);
     TMenor := MaxValue([TMenor, T1]);
     TMayor := MinValue([TMayor, T2]);
     if TMenor > TMayor then exit;
     end;
    
     end;
    
     P := gr_Suma(O, gr_Multiplica(D, TMenor));
     result := true;
    end;
    
    //------------------------------------------------------------------------------
    function ch_IntersecaPlanoPlano(
     const P1, P2: gr_rPlano3D;
     var P: gr_rVector3D;
     var D: gr_rVector3D
     ): Boolean;
    
     var
     D1: Single;
    
    begin
     result := false;
     D := gr_ProductoCruz(P1.N, P2.N);
    
     D1 := gr_ProductoPunto(D, D);
     if D1 < gr_EPSILON then exit;
    
     P := gr_Divide(gr_ProductoCruz(gr_Resta(
     gr_Multiplica(P2.N, P1.PP), gr_Multiplica(P1.N, P2.PP)), D), D1);
     result := true;
    end;
    
    //------------------------------------------------------------------------------
    function ch_IntersecaPlanoPlanoPlano(
     const P1, P2, P3: gr_rPlano3D;
     var P: gr_rVector3D
     ): Boolean;
    
     var
     U: gr_rVector3D;
     Denom: Single;
    
    begin
     result := false;
     U := gr_ProductoCruz(P2.N, P3.N);
     Denom := gr_ProductoPunto(P1.N, U);
     if Abs(Denom) < gr_EPSILON then exit;
     P := gr_Divide(gr_Suma(gr_Multiplica(U, P1.PP), gr_ProductoCruz(
     P1.N, gr_Resta(gr_Multiplica(P2.N, P3.PP),
     gr_Multiplica(P3.N, P2.PP)))), Denom);
     result := true;
    end;
    
    //------------------------------------------------------------------------------
    // Basado en:
    // http://www.cs.lth.se/home/Tomas_Akenine_Moller/code/
    function ch_TraslapaPlanoCajaEje3(
     const P: gr_rPlano3D;
     const C: ch_rCajaEje3
     ): Boolean;
    
     var
     I: Integer;
     VMenor,VMayor: gr_rVector3D;
     V: Single;
    
    begin
     result := false;
    
     for I := 0 to 2 do
     begin
     V := C.C.M[I];
    
     if P.N.M[I] > 0 then
     begin
     VMenor.M[I] := -C.R.M[I]-V;
     VMayor.M[I] := C.R.M[I]-V;
     end else
     begin
     VMenor.M[I] := C.R.M[I]-V;
     VMayor.M[I] := -C.R.M[I]-V;
     end;
    
     end;
    
     if gr_ProductoPunto(P.N, VMenor) > 0 then exit;
     if gr_ProductoPunto(P.N, VMayor) < 0 then exit;
    
     result := true;
    end;
    
    //------------------------------------------------------------------------------
    // Basado en:
    // http://jgt.akpeters.com/papers/Moller97/
    function ch_IntersecaTriánguloTriángulo(
     const TA1, TA2, TA3, // Puntos del triángulo A
     TB1, TB2, TB3: gr_rVector3D // Puntos del triángulo B
     ): Boolean;
    
     var
     E1, E2, N1, N2, DV: gr_rVector3D;
     IS1, IS2: array [0..1] of Single;
     D1, D2, DU0, DU1, DU2, DV0, DV1, DV2: Single;
     DU01, DU02, DV01, DV02: Single;
     VP0, VP1, VP2: Single;
     UP0, UP1, UP2: Single;
     BB, CC, Mayor: Single;
     A, B, C, X0, X1: Single;
     D, E, F, Y0, Y1: Single;
     XX, YY, XXYY, T: Single;
     I: Integer;
    
     function CalculaIntervalos(
     const VV0, VV1, VV2, D0, D1, D2, D0D1, D0D2: Single;
     var A, B, C, X0, X1: Single;
     var Resultado: Boolean
     ): Boolean;
     begin
     result := false;
    
     if D0D1 > 0 then
     begin
     A := VV2;
     B := (VV0-VV2)*D2;
     C := (VV1-VV2)*D2;
     X0 := D2-D0;
     X1 := D2-D1;
     end else
     if D0D2 > 0 then
     begin
     A := VV1;
     B := (VV0-VV1)*D1;
     C := (VV2-VV1)*D1;
     X0 := D1-D0;
     X1 := D1-D2;
     end else
     if (D1*D2 > 0) or (D0 <> 0) then
     begin
     A := VV0;
     B := (VV1-VV0)*D0;
     C := (VV2-VV0)*D0;
     X0 := D0-D1;
     X1 := D0-D2;
     end else
     if D1 <> 0 then
     begin
     A := VV1;
     B := (VV0-VV1)*D1;
     C := (VV2-VV1)*D1;
     X0 := D1-D0;
     X1 := D1-D2;
     end else
     if D2 <> 0 then
     begin
     A := VV2;
     B := (VV0-VV2)*D2;
     C := (VV1-VV2)*D2;
     X0 := D2-D0;
     X1 := D2-D1;
     end else
     begin
     result := true;
     Resultado := gr_TriángulosCoplanares(N1, TA1, TA2, TA3, TB1, TB2, TB3);
     end;
    
     end;
    
    begin
     result := false;
     E1 := gr_Resta(TA2, TA1);
     E2 := gr_Resta(TA3, TA1);
     N1 := gr_ProductoCruz(E1, E2);
     D1 := -gr_ProductoPunto(N1, TA1);
    
     DU0 := gr_ProductoPunto(N1, TB1)+D1;
     DU1 := gr_ProductoPunto(N1, TB2)+D1;
     DU2 := gr_ProductoPunto(N1, TB3)+D1;
    
     if Abs(DU0) < gr_EPSILON then DU0 := 0;
     if Abs(DU1) < gr_EPSILON then DU1 := 0;
     if Abs(DU2) < gr_EPSILON then DU2 := 0;
    
     DU01 := DU0*DU1;
     DU02 := DU0*DU2;
    
     if (DU01 > 0) and (DU02 > 0) then exit;
    
     E1 := gr_Resta(TB2, TB1);
     E2 := gr_Resta(TB3, TB1);
     N2 := gr_ProductoCruz(E1, E2);
     D2 := -gr_ProductoPunto(N2, TB1);
    
     DV0 := gr_ProductoPunto(N2, TA1)+D2;
     DV1 := gr_ProductoPunto(N2, TA2)+D2;
     DV2 := gr_ProductoPunto(N2, TA3)+D2;
    
     if Abs(DV0) < gr_EPSILON then DV0 := 0;
     if Abs(DV1) < gr_EPSILON then DV1 := 0;
     if Abs(DV2) < gr_EPSILON then DV2 := 0;
    
     DV01 := DV0*DV1;
     DV02 := DV0*DV2;
    
     if (DV01 > 0) and (DV02 > 0) then exit;
    
     DV := gr_ProductoCruz(N1, N2);
    
     Mayor := Abs(DV.M[0]);
     I := 0;
     BB := Abs(DV.M[1]);
     CC := Abs(DV.M[2]);
    
     if BB > Mayor then
     begin
     Mayor := BB;
     I := 1;
     end;
    
     if CC > Mayor then
     begin
    // Mayor := CC;
     I := 2;
     end;
    
     VP0 := TA1.M[I];
     VP1 := TA2.M[I];
     VP2 := TA3.M[I];
    
     UP0 := TB1.M[I];
     UP1 := TB2.M[I];
     UP2 := TB3.M[I];
    
     if CalculaIntervalos(VP0, VP1, VP2, DV0, DV1, DV2, DV01, DV02, A, B, C,
     X0, X1, result) then exit;
     if CalculaIntervalos(UP0, UP1, UP2, DU0, DU1, DU2, DU01, DU02, D, E, F,
     Y0, Y1, result) then exit;
    
     XX := X0*X1;
     YY := Y0*Y1;
     XXYY := XX*YY;
    
     T := A*XXYY;
     IS1[0] := T+B*X1*YY;
     IS1[1] := T+C*X0*YY;
    
     T := D*XXYY;
     IS2[0] := T+E*XX*Y1;
     IS2[1] := T+F*XX*Y0;
    
     cm_Asciente(IS1[0], IS1[1]);
     cm_Asciente(IS2[0], IS2[1]);
    
     if (IS1[1] < IS2[0]) or (IS2[1] < IS1[0]) then exit;
     result := false;
    end;
    
    //------------------------------------------------------------------------------
    // Tomado de:
    // http://www.cs.lth.se/home/Tomas_Akenine_Moller/code/
    function ch_TraslapaTriánguloCajaEje3(
     const T1, T2, T3: gr_rVector3D; // Puntos del triángulo
     const C: ch_rCajaEje3
     ): Boolean;
    
     var
     V1, V2, V3: gr_rVector3D;
     Menor, Mayor, P1, P2, P3, R, FEX, FEY, FEZ: Single;
     E1, E2, E3: gr_rVector3D;
    
     function PruebaEjeX01(
     A, B, FA, FB: Single
     ): Boolean;
     begin
     P1 := A*V1.Y-B*V1.Z;
     P3 := A*V3.Y-B*V3.Z;
    
     if P1 < P3 then
     begin
     Menor := P1;
     Mayor := P3;
     end else
     begin
     Menor := P3;
     Mayor := P1;
     end;
    
     R := FA*C.R.Y+FB*C.R.Z;
     result := (Menor > R) or (Mayor < -R);
     end;
    
     function PruebaEjeX2(
     A, B, FA, FB: Single
     ): Boolean;
     begin
     P1 := A*V1.Y-B*V1.Z;
     P2 := A*V2.Y-B*V2.Z;
    
     if P1 < P2 then
     begin
     Menor := P1;
     Mayor := P2;
     end else
     begin
     Menor := P2;
     Mayor := P1;
     end;
    
     R := FA*C.R.Y+FB*C.R.Z;
     result := (Menor > R) or (Mayor < -R);
     end;
    
     function PruebaEjeY02(
     A, B, FA, FB: Single
     ): Boolean;
     begin
     P1 := -A*V1.X+B*V1.Z;
     P3 := -A*V3.X+B*V3.Z;
    
     if P1 < P3 then
     begin
     Menor := P1;
     Mayor := P3;
     end else
     begin
     Menor := P3;
     Mayor := P1;
     end;
    
     R := FA*C.R.X+FB*C.R.Z;
     result := (Menor > R) or (Mayor < -R);
     end;
    
     function PruebaEjeY1(
     A, B, FA, FB: Single
     ): Boolean;
     begin
     P1 := -A*V1.X+B*V1.Z;
     P2 := -A*V2.X+B*V2.Z;
    
     if P1 < P2 then
     begin
     Menor := P1;
     Mayor := P2;
     end else
     begin
     Menor := P2;
     Mayor := P1;
     end;
    
     R := FA*C.R.X+FB*C.R.Z;
     result := (Menor > R) or (Mayor < -R);
     end;
    
     function PruebaEjeZ12(
     A, B, FA, FB: Single
     ): Boolean;
     begin
     P2 := A*V2.X-B*V2.Y;
     P3 := A*V3.X-B*V3.Y;
    
     if P3 < P2 then
     begin
     Menor := P3;
     Mayor := P2;
     end else
     begin
     Menor := P2;
     Mayor := P3;
     end;
    
     R := FA*C.R.X+FB*C.R.Y;
     result := (Menor > R) or (Mayor < -R);
     end;
    
     function PruebaEjeZ0(
     A, B, FA, FB: Single
     ): Boolean;
     begin
     P1 := A*V1.X-B*V1.Y;
     P2 := A*V2.X-B*V2.Y;
    
     if P1 < P2 then
     begin
     Menor := P1;
     Mayor := P2;
     end else
     begin
     Menor := P2;
     Mayor := P1;
     end;
    
     R := FA*C.R.X+FB*C.R.Y;
     result := (Menor > R) or (Mayor < -R);
     end;
    
     procedure Extremos(
     X1, X2, X3: Single
     );
     begin
     Menor := X1;
     Mayor := X1;
     if X2 < Menor then Menor := X2;
     if X2 > Mayor then Mayor := X2;
     if X3 < Menor then Menor := X3;
     if X3 > Mayor then Mayor := X3;
     end;
    
    begin
     result := false;
     V1 := gr_Resta(T1, C.C);
     V2 := gr_Resta(T2, C.C);
     V3 := gr_Resta(T3, C.C);
    
     E1 := gr_Resta(V2, V1);
     E2 := gr_Resta(V3, V2);
     E3 := gr_Resta(V1, V3);
    
     FEX := Abs(E1.X);
     FEY := Abs(E1.Y);
     FEZ := Abs(E1.Z);
     if PruebaEjeX01(E1.Z, E1.Y, FEZ, FEY) then exit;
     if PruebaEjeY02(E1.Z, E1.X, FEZ, FEX) then exit;
     if PruebaEjeZ12(E1.Y, E1.X, FEY, FEX) then exit;
    
     FEX := Abs(E2.X);
     FEY := Abs(E2.Y);
     FEZ := Abs(E2.Z);
     if PruebaEjeX01(E2.Z, E2.Y, FEZ, FEY) then exit;
     if PruebaEjeY02(E2.Z, E2.X, FEZ, FEX) then exit;
     if PruebaEjeZ0(E2.Y, E2.X, FEY, FEX) then exit;
    
     FEX := Abs(E3.X);
     FEY := Abs(E3.Y);
     FEZ := Abs(E3.Z);
     if PruebaEjeX2(E3.Z, E3.Y, FEZ, FEY) then exit;
     if PruebaEjeY1(E3.Z, E3.X, FEZ, FEX) then exit;
     if PruebaEjeZ12(E3.Y, E3.X, FEY, FEX) then exit;
    
     Extremos(V1.X, V2.X, V3.X);
     if (Menor > C.R.X) or (Mayor < -C.R.X) then exit;
    
     Extremos(V1.Y, V2.Y, V3.Y);
     if (Menor > C.R.Y) or (Mayor < -C.R.Y) then exit;
    
     Extremos(V1.Z, V2.Z, V3.Z);
     if (Menor > C.R.Z) or (Mayor < -C.R.Z) then exit;
    
     if not ch_TraslapaPlanoCajaEje3(gr_CreaPlano3D(gr_ProductoCruz(E1, E2),
     gr_ProductoPunto(E1, E2)), ch_CreaCajaEje3(V1, C.R)) then exit;
    
     result := true;
    end;
    
    //------------------------------------------------------------------------------
    function ch_TraslapaEsferaPlano(
     const E: ch_rEsfera;
     const P: gr_rPlano3D
     ): Boolean;
    begin
     result := Abs(gr_ProductoPunto(E.C, P.N)-P.PP) <=
     E.R;
    end;
    
    //------------------------------------------------------------------------------
    function ch_TraslapaEsferaMedioPlano(
     const E: ch_rEsfera;
     const P: gr_rPlano3D
     ): Boolean;
    begin
     result := gr_ProductoPunto(E.C, P.N)-P.PP <= E.R;
    end;
    
    //------------------------------------------------------------------------------
    function ch_TraslapaEsferaTriángulo(
     const E: ch_rEsfera;
     const T1, T2, T3: gr_rVector3D; // Puntos del triángulo
     var P: gr_rVector3D
     ): Boolean;
    
     var
     V: gr_rVector3D;
    
    begin
     ch_MasCercaPuntoTriángulo(E.C, T1, T2, T3, P);
     V := gr_Resta(P, E.C);
     result := gr_ProductoPunto(V, V) <= E.R*E.R;
    end;
    
    //------------------------------------------------------------------------------
    function ch_TraslapaEsferaEsfera(
     const E1, E2: ch_rEsfera
     ): Boolean;
    
     var
     D2, R: Single;
    
    begin
     D2 := gr_DistanciaCuadrada(E1.C, E2.C);
     R := E1.R+E2.R;
     result := D2 <= R*R;
    end;
    
    //------------------------------------------------------------------------------
    function ch_TraslapaEsferaCajaEje1(
     const E: ch_rEsfera;
     const C: ch_rCajaEje1
     ): Boolean;
    begin
     result := ch_DistanciaCuadradaPuntoCajaEje(E.C, C) <= E.R*E.R;
    end;
    
    //------------------------------------------------------------------------------
    function ch_TraslapaEsferaCajaEje1(
     const E: ch_rEsfera;
     const C: ch_rCajaEje1;
     var P: gr_rVector3D
     ): Boolean;
    
     var
     V: gr_rVector3D;
    
    begin
     ch_MasCercaPuntoCajaEje(E.C, C, P);
     V := gr_Resta(P, E.C);
     result := gr_ProductoPunto(V, V) <= E.R*E.R;
    end;
    
    //------------------------------------------------------------------------------
    function ch_TraslapaEsferaCajaLibre(
     const E: ch_rEsfera;
     const C: ch_rCajaLibre;
     var P: gr_rVector3D
     ): Boolean;
    
     var
     V: gr_rVector3D;
    
    begin
     ch_MasCercaPuntoCajaLibre(E.C, C, P);
     V := gr_Resta(P, E.C);
     result := gr_ProductoPunto(V, V) <= E.R*E.R;
    end;
    
    //------------------------------------------------------------------------------
    function ch_TraslapaEsferaCapsula(
     const E: ch_rEsfera;
     const C: ch_rCapsula
     ): Boolean;
    
     var
     D2, R: Single;
    
    begin
     D2 := ch_DistanciaCuadradaPuntoSegmento(C.A, C.B, E.C);
     R := E.R+C.R;
     result := D2 <= R*R;
    end;
    
    //------------------------------------------------------------------------------
    function ch_TraslapaEsferaPoligono(
     const E: ch_rEsfera;
     const P: gr_rPoligono3D
     ): Boolean;
    
     var
     M: gr_rPlano3D;
     I, J, K: Integer;
     T: Single;
     que: gr_rVector3D;
    
    begin
     result := false;
     M.N := gr_Normaliza(gr_ProductoCruz(gr_Resta(P.V[1], P.V[0]), gr_Resta(
     P.V[2], P.V[0])));
     M.PP := -gr_ProductoPunto(M.N, P.V[0]);
     if not ch_TraslapaEsferaPlano(E, M) then exit;
    
     K := Length(P.V);
     I := 0;
     J := K-1;
    
     while I < K do
     begin
     if ch_IntersecaRayoEsfera(P.V[J], gr_Resta(P.V[I], P.V[J]), E, T, que) and
     (T <= 1) then exit;
     J := I;
     Inc(I);
     end;
    
     ch_MasCercaPuntoPlano(E.C, M, que);
     result := ch_ContienePuntoPoligono(que, P);
    end;
    
    //------------------------------------------------------------------------------
    function ch_ContieneCajaEje1Punto(
     const C: ch_rCajaEje1;
     const P: gr_rVector3D
     ): Boolean;
    begin
     result :=
     ((P.X >= C.Menor.X) and (P.X <= C.Mayor.X)) and
     ((P.Y >= C.Menor.Y) and (P.Y <= C.Mayor.Y)) and
     ((P.Z >= C.Menor.Z) and (P.Z <= C.Mayor.Z));
    end;
    
    //------------------------------------------------------------------------------
    function ch_TraslapaCajaEje1Plano(
     const C: ch_rCajaEje1;
     const P: gr_rPlano3D
     ): Boolean;
    
     var
     C1, E: gr_rVector3D;
     R, S: Single;
    
    begin
     C1 := gr_Multiplica(gr_Suma(C.Mayor, C.Menor), 0.5);
     E := gr_Resta(C.Mayor, C1);
    
     R := E.X*Abs(P.N.X)+E.Y*Abs(P.N.Y)+E.Z*Abs(P.N.Z);
     S := gr_ProductoPunto(P.N, C1)-P.PP;
    
     result := Abs(S) <= R;
    end;
    
    //------------------------------------------------------------------------------
    function ch_TraslapaCajaEje1CajaEje1(
     const C1, C2: ch_rCajaEje1
     ): Boolean;
    begin
     result :=
     (C1.Mayor.X >= C2.Menor.X) and (C1.Menor.X <= C2.Mayor.X) and
     (C1.Mayor.Y >= C2.Menor.Y) and (C1.Menor.Y <= C2.Mayor.Y) and
     (C1.Mayor.Z >= C2.Menor.Z) and (C1.Menor.Z <= C2.Mayor.Z);
    end;
    
    //------------------------------------------------------------------------------
    function ch_TraslapaCajaEje2CajaEje2(
     const C1, C2: ch_rCajaEje2
     ): Boolean;
    
     var
     T: Single;
    
    begin
     result := false;
     T := C1.Menor.X-C2.Menor.X;
     if (T > C2.D.X) or (-T > C1.D.X) then exit;
     T := C1.Menor.Y-C2.Menor.Y;
     if (T > C2.D.Y) or (-T > C1.D.Y) then exit;
     T := C1.Menor.Z-C2.Menor.Z;
     if (T > C2.D.Z) or (-T > C1.D.Z) then exit;
     result := true;
    end;
    
    //------------------------------------------------------------------------------
    function ch_TraslapaCajaEje3CajaEje3(
     const C1, C2: ch_rCajaEje3
     ): Boolean;
    begin
     result :=
     (Abs(C1.C.X-C2.C.X) <= (C1.R.X+C2.R.X)) and
     (Abs(C1.C.Y-C2.C.Y) <= (C1.R.Y+C2.R.Y)) and
     (Abs(C1.C.Z-C2.C.Z) <= (C1.R.Z+C2.R.Z));
    end;
    
    //------------------------------------------------------------------------------
    function ch_TraslapaCajaLibrePlano(
     const C: ch_rCajaLibre;
     const P: gr_rPlano3D
     ): Boolean;
    
     var
     R, S: Single;
    
    begin
     R :=
     C.R.X*Abs(gr_ProductoPunto(P.N, C.U[0]))+
     C.R.Y*Abs(gr_ProductoPunto(P.N, C.U[1]))+
     C.R.Z*Abs(gr_ProductoPunto(P.N, C.U[2]));
     S := gr_ProductoPunto(P.N, C.C)-P.PP;
     result := Abs(S) <= R;
    end;
    
    //------------------------------------------------------------------------------
    function ch_TraslapaCajaLibreCajaLibre(
     const C1, C2: ch_rCajaLibre
     ): Boolean;
    
     var
     R1, R2: Single;
     R, AR: gr_rMatriz3x3;
     I, J: Integer;
     T: gr_rVector3D;
    
    begin
     result := false;
    
     for I := 0 to 2 do
     for J := 0 to 2 do
     R.M[I,J] := gr_ProductoPunto(C1.U[I], C2.U[J]);
    
     T := gr_Resta(C2.C, C1.C);
     T := gr_CreaVector3D(gr_ProductoPunto(T, C1.U[0]), gr_ProductoPunto(T,
     C1.U[1]), gr_ProductoPunto(T, C1.U[2]));
    
     for I := 0 to 2 do
     for J := 0 to 2 do
     AR.M[I,J] := Abs(R.M[I,J])+gr_EPSILON;
    
     for I := 0 to 2 do
     begin
     R1 := C1.R.M[I];
     R2 := C2.R.M[0]*AR.M[I,0]+C2.R.M[1]*AR.M[I,1]+C2.R.M[2]*AR.M[I,2];
     if Abs(T.M[I]) > R1+R2 then exit;
     end;
    
     for I := 0 to 2 do
     begin
     R1 := C1.R.M[0]*AR.M[0,I]+C1.R.M[1]*AR.M[1,I]+C1.R.M[2]*AR.M[2,I];
     R2 := C2.R.M[I];
     if Abs(T.M[0]*R.M[0,I]+T.M[1]*R.M[1,I]+T.M[2]*R.M[2,I]) > R1+R2 then exit;
     end;
    
     R1 := C1.R.M[1]*AR.M[2,0]+C1.R.M[2]*AR.M[1,0];
     R2 := C2.R.M[1]*AR.M[0,2]+C2.R.M[2]*AR.M[0,1];
     if Abs(T.M[2]*R.M[1,0]-T.M[1]*R.M[2,0]) > R1+R2 then exit;
    
     R1 := C1.R.M[1]*AR.M[2,1]+C1.R.M[2]*AR.M[1,1];
     R2 := C2.R.M[0]*AR.M[0,2]+C2.R.M[2]*AR.M[0,0];
     if Abs(T.M[2]*R.M[1,1]-T.M[1]*R.M[2,1]) > R1+R2 then exit;
    
     R1 := C1.R.M[1]*AR.M[2,2]+C1.R.M[2]*AR.M[1,2];
     R2 := C2.R.M[0]*AR.M[0,1]+C2.R.M[1]*AR.M[0,0];
     if Abs(T.M[2]*R.M[1,2]-T.M[1]*R.M[2,2]) > R1+R2 then exit;
    
     R1 := C1.R.M[0]*AR.M[2,0]+C1.R.M[2]*AR.M[0,0];
     R2 := C2.R.M[1]*AR.M[1,2]+C2.R.M[2]*AR.M[1,1];
     if Abs(T.M[0]*R.M[2,0]-T.M[2]*R.M[0,0]) > R1+R2 then exit;
    
     R1 := C1.R.M[0]*AR.M[2,1]+C1.R.M[2]*AR.M[0,1];
     R2 := C2.R.M[0]*AR.M[1,2]+C2.R.M[2]*AR.M[1,0];
     if Abs(T.M[0]*R.M[2,1]-T.M[2]*R.M[0,1]) > R1+R2 then exit;
    
     R1 := C1.R.M[0]*AR.M[2,2]+C1.R.M[2]*AR.M[0,2];
     R2 := C2.R.M[0]*AR.M[1,1]+C2.R.M[1]*AR.M[1,0];
     if Abs(T.M[0]*R.M[2,2]-T.M[2]*R.M[0,2]) > R1+R2 then exit;
    
     R1 := C1.R.M[0]*AR.M[1,0]+C1.R.M[1]*AR.M[0,0];
     R2 := C2.R.M[1]*AR.M[2,2]+C2.R.M[2]*AR.M[2,1];
     if Abs(T.M[1]*R.M[0,0]-T.M[0]*R.M[1,0]) > R1+R2 then exit;
    
     R1 := C1.R.M[0]*AR.M[1,1]+C1.R.M[1]*AR.M[0,1];
     R2 := C2.R.M[0]*AR.M[2,2]+C2.R.M[2]*AR.M[2,0];
     if Abs(T.M[1]*R.M[0,1]-T.M[0]*R.M[1,1]) > R1+R2 then exit;
    
     R1 := C1.R.M[0]*AR.M[1,2]+C1.R.M[1]*AR.M[0,2];
     R2 := C2.R.M[0]*AR.M[2,1]+C2.R.M[1]*AR.M[2,0];
     if Abs(T.M[1]*R.M[0,2]-T.M[0]*R.M[1,2]) > R1+R2 then exit;
    
     result := true;
    end;
    
    //------------------------------------------------------------------------------
    function ch_TraslapaCapsulaCapsula(
     const C1, C2: ch_rCapsula
     ): Boolean;
    
     var
     S, T, D2, R: Single;
     PC1, PC2: gr_rVector3D;
    
    begin
     D2 := ch_MasCercaSegmentoSegmento(C1.A, C1.B, C2.A, C2.B, S, T, PC1, PC2);
     R := C1.R+C2.R;
     result := D2 <= R*R;
    end;
    
    //------------------------------------------------------------------------------
    function ch_TraslapaPolitopoPolitopo(
     const P1, P2: ch_rPolitopo // Politopos del mismo orden par
     ): Boolean;
    
     var
     I: Integer;
    
    begin
     result := false;
    
     for I := 0 to (Length(P1.Menores) shr 1)-1 do
     begin
     if (P1.Menores[I] > P2.Mayores[I]) or (P1.Mayores[I] < P2.Menores[I]) then
     exit;
     end;
    
     result := true;
    end;
    
    end.
    Mañana te explico, y te indico donde hay recursos que te puedan ayudar. Ya está un poco tarde por aca.

  13. #13
    Expulsado
    Fecha de ingreso
    Dec 2010
    Ubicación
    En matrix
    Mensajes
    1,681

    Re: Busco ayuda para desarrollar video juego (diseñadores, modeladores, músicos)

    Bueno pues espero con ganas que me contextes mañana, mientras mirare ese codigo, creyendome que lo estoy entendiendo (mi primer contacto hoy con este lenguaje y ya tengo ganas de aprenderlo, aunque antes quiero acabar el juego que estoy haciendo),:D.

    Pues lo de las colisiones yo en blitz conseguí lo de que la esfera choque contra un poligono (sin usar las colisiones del blitz), pero no sabia que fuera tan complejo a nivel de un motor. Realmente quería entender como colisionar una esfera contra un poligono porque así podría invertir el proceso, es decir, lo que quería era lo contrario --> poligono a esfera,ya que blitz3d no soporta este tipo de colision.
    Y no acabo de entender lo de las colisiones y el hardware..

    Con el tema de ayudarte....va a ser que no podria..por lo menos de momento,:D para cuando pueda hacerlo ya habras acabado supongo.

    Saludos y muchas gracias
    Última edición por aprendiz; 19-07-2011 a las 06:54

  14. #14
    Miembro Nuevo
    Fecha de ingreso
    Jul 2011
    Mensajes
    17

    Lightbulb Re: Busco ayuda para desarrollar video juego (diseñadores, modeladores, músicos)

    Hola amigo aprendiz, aquí me encontré varios recursos que te pueden ser útiles para aprender Object Pascal:
    http://www.freepascal.es/index.php
    http://www.freepascal.es/cursos.php

    Basicamente para probar si un polígono, choca con una esfera, necesitas descomponer la maya en sus triángulos, y probar cada triángulo contra la esfera. Esto es un poco lento en Blitz, pero se puede lograr. Si la maya es muy compleja, puedes usar una versión en bajos polígonos para obtener una apróximación más rápido. Si quieres mejor abre un tema aparte y te ayudo en lo que pueda.

    Bueno, yo también necesito terminar mi juego primero. Talvez en el futuro podamos hablar del motor nuevamente.

    Saludos!
    -Marco

  15. #15
    Expulsado
    Fecha de ingreso
    Dec 2010
    Ubicación
    En matrix
    Mensajes
    1,681

    Re: Busco ayuda para desarrollar video juego (diseñadores, modeladores, músicos)

    Pues gracias por tu ayuda.
    Pues si me esperas para continuar el motor mejor, me haría mucha ilusion poder ayudar en un proyecto de ese tamaño, y aprenderia bastante también, para poder crear yo un motor después.

    Releyendo uno de tus mensajes, en uno que me ponias que aprendiera protocolos, transmisiones etc, a que te referias? para hacer un juego en línea dices?
    El tema de las colisiones podemos abrir un tema en la sección videojuegos, si te parece, y hay te muestro mi código .bb y tu me dices que hago mal, o que no hago,ok?

    pd: piensas vender el motor?

    edito: ya había abierto un hilo de colisiones blitz, ahora puse los codigos que cree, echos íntegramente por mi,:D. Pero como podrás ver, tienen multiples fallos, además de que las fps van a caer muy rápido si incluyo física.bb en un juego. Bueno, espero que puedas ayudarme porque pause el proyecto que no sabía como continuar. Esta aquí: BLITZ basic : colisiones
    Última edición por aprendiz; 19-07-2011 a las 21:08

Página 1 de 2 12 ÚltimoÚltimo

Temas similares

  1. Respuestas: 0
    Último mensaje: 09-08-2016, 10:37
  2. Ofertas de Trabajo Busco diseñadores/modeladores/concept para proyecto personal
    Por knack en el foro Colaboraciones e Iniciativas
    Respuestas: 0
    Último mensaje: 03-02-2016, 14:43
  3. Buscamos gente para desarrollar juego de pc
    Por Dani Diseñador en el foro Colaboraciones e Iniciativas
    Respuestas: 20
    Último mensaje: 18-05-2010, 13:25
  4. busco modeladores para un juego
    Por adrimat08 en el foro Colaboraciones e Iniciativas
    Respuestas: 1
    Último mensaje: 28-08-2009, 02:11
  5. 3ds Max busco modeladores para un juego
    Por adrimat08 en el foro Modelado
    Respuestas: 1
    Último mensaje: 28-08-2009, 02:11

Actualmente estos son sus permisos de publicación en el foro.

  • -No puedes crear nuevos temas al no estar registrado o no haber iniciado sesión en el foro.
  • -No puedes responder temas al no estar registrado o no haber iniciado sesión en el foro.
  • -No puedes subir archivos adjuntos al no estar registrado o no haber iniciado sesión en el foro.
  • -No puedes editar tus mensajes al no estar registrado o no haber iniciado sesión en el foro.
  •