Solved

DirectX floating point errors

Posted on 1998-03-14
8
480 Views
Last Modified: 2008-02-01
I've got a problem using DirectX3D.  I've copied an example from the help and transformed it a little to work in c++builder.  And when running the program I occassionaly get an Invalid Floating point operation error or a divide by zero error.  The time it happens depends on the type of object I load in my 3d space, and the position of the objects.  With a cube it doesn't happen, with a sphere it most of the time does.

I had exactly the same problem when I tried this with OpenGL.

With OpenGL I could see (by debugging) that the error occurs inside the OpenGL a function call (for rendering I think - can't remember).

Any suggestions would be appreciated,
Thx

Odie
0
Comment
Question by:Odie
8 Comments
 
LVL 10

Expert Comment

by:rbr
Comment Utility
Pls send some code!!!
0
 
LVL 1

Author Comment

by:Odie
Comment Utility
I thought you would be little with just a part of the code, but I didn't want to force anyone into it from the beginning.  Anyway: here's the whole stuff:

#define INITGUID           // Must precede other defines and includes
//---------------------------------------------------------------------------
#include <vcl\vcl.h>
#pragma hdrstop

#include "MainUnit.h"
//---------------------------------------------------------------------------
#pragma resource "*.dfm"
TForm1 *Form1;

#include <math.h>
#include <windows.h>
#include <malloc.h>
#include <d3drmwin.h>

#define MAX_DRIVERS 5           // Maximum D3D drivers expected

// Global variables
LPDIRECT3DRM D3DRM;
LPDIRECTDRAWCLIPPER lpDDClipper;
struct {
  LPDIRECT3DRMDEVICE Device;
  LPDIRECT3DRMVIEWPORT ViewPort;
  LPDIRECT3DRMFRAME FrameScene;
  LPDIRECT3DRMFRAME FrameCamera;

  GUID DriverGUID[MAX_DRIVERS];
  char DriverName[MAX_DRIVERS][50];
  int  NumDrivers;
  int  CurrDriver;

  BOOL bQuit;
  BOOL bMinimized;

  int BPP;

  // Non 3d-data
  LPDIRECT3DRMFRAME FrameBol1;
  LPDIRECT3DRMFRAME FrameBol2;
  double Bol1X, Bol2X;
  double Org1X, Org2X;
  double Mass1, Mass2;
  double Charge1, Charge2;
  double MassMid;
  double ChargeMid;
  double ForceMid;
  double RXOrg;
  double Grav, TimeScale, Elec;

  long Precision;

//  double Radia

} ProgramData;
//----------------------------------------------------------------------------
static DWORD BPPToDDBD(int bpp) {
  switch(bpp) {
    case  1: return DDBD_1;
    case  2: return DDBD_2;
    case  4: return DDBD_4;
    case  8: return DDBD_8;
    case 16: return DDBD_16;
    case 24: return DDBD_24;
    case 32: return DDBD_32;
    default: return 0;
  }
}
//---------------------------------------------------------------------------
static HRESULT WINAPI enumDeviceFunc(LPGUID lpGuid, LPSTR lpDeviceDescription,
                                      LPSTR lpDeviceName, LPD3DDEVICEDESC lpHWDesc,
                                       LPD3DDEVICEDESC lpHELDesc, LPVOID lpContext)
{
  static BOOL hardware = FALSE; // Current start driver is hardware
  static BOOL mono = FALSE;     // Current start driver is mono light
  LPD3DDEVICEDESC lpDesc;
  int *lpStartDriver = (int *)lpContext;

  lpDesc = lpHWDesc->dcmColorModel ? lpHWDesc : lpHELDesc;

  if (!(lpDesc->dwDeviceRenderBitDepth & BPPToDDBD(ProgramData.BPP)))
    return D3DENUMRET_OK;

  memcpy(&ProgramData.DriverGUID[ProgramData.NumDrivers], lpGuid, sizeof(GUID));
  lstrcpy(&ProgramData.DriverName[ProgramData.NumDrivers][0], lpDeviceName);

  if (*lpStartDriver == -1) {
    *lpStartDriver = ProgramData.NumDrivers;
    hardware = lpDesc == lpHWDesc ? TRUE : FALSE;
    mono = lpDesc->dcmColorModel & D3DCOLOR_MONO ? TRUE : FALSE;
  } else if (lpDesc == lpHWDesc && !hardware) {
    *lpStartDriver = ProgramData.NumDrivers;
    hardware = lpDesc == lpHWDesc ? TRUE : FALSE;
    mono = lpDesc->dcmColorModel & D3DCOLOR_MONO ? TRUE : FALSE;
  } else if ((lpDesc == lpHWDesc && hardware ) || (lpDesc == lpHELDesc && !hardware)) {
    if (lpDesc->dcmColorModel == D3DCOLOR_MONO && !mono) {
      *lpStartDriver = ProgramData.NumDrivers;
      hardware = lpDesc == lpHWDesc ? TRUE : FALSE;
      mono = lpDesc->dcmColorModel & D3DCOLOR_MONO ? TRUE : FALSE;
    }
  }
  ProgramData.NumDrivers++;

  if (ProgramData.NumDrivers == MAX_DRIVERS) return (D3DENUMRET_CANCEL);
  return (D3DENUMRET_OK);
}
//---------------------------------------------------------------------------
static BOOL EnumDrivers(HWND win)
{
  LPDIRECTDRAW DD;
  LPDIRECT3D D3D;
  HRESULT rval;

  DirectDrawCreate(NULL, &DD, NULL);
  rval = DD->QueryInterface(IID_IDirect3D, (void **) &D3D);
  if (rval != DD_OK) {
    DD->Release();
    return FALSE;
  }

  ProgramData.CurrDriver = -1;
  D3D->EnumDevices(enumDeviceFunc, &ProgramData.CurrDriver);

  if (ProgramData.NumDrivers == 0) {
    return FALSE;
  }
  D3D->Release();
  DD->Release();

  return TRUE;
}
//---------------------------------------------------------------------------
BOOL SetRenderState(void) {
  HRESULT rval;

  rval = ProgramData.Device->SetQuality(D3DRMLIGHT_ON | D3DRMFILL_SOLID | D3DRMSHADE_GOURAUD);
  if (rval != D3DRM_OK) {
    return FALSE;
  }

  // If you want to change the dithering mode, call SetDither here.
  ProgramData.Device->SetDither(false);

  // If you want a texture quality other than D3DRMTEXTURE_NEAREST
  // (the default value), call SetTextureQuality here.
  return TRUE;
}
//----------------------------------------------------------------------------
static BOOL CreateDevAndView(LPDIRECTDRAWCLIPPER lpDDClipper, int driver,
                              int width, int height)
{
  HRESULT rval;

  D3DRM->CreateDeviceFromClipper(lpDDClipper, &ProgramData.DriverGUID[driver],
                                  width, height, &ProgramData.Device);
  width = ProgramData.Device->GetWidth();
  height = ProgramData.Device->GetHeight();

  rval = D3DRM->CreateViewport(ProgramData.Device, ProgramData.FrameCamera, 0, 0,
                                width, height, &ProgramData.ViewPort);
  if (rval != D3DRM_OK) {
    ProgramData.Device->Release();
    return FALSE;
  }
  rval = ProgramData.ViewPort->SetBack(D3DVAL(5000.0));
  if (rval != D3DRM_OK) {
    ProgramData.Device->Release();
    ProgramData.ViewPort->Release();
    return FALSE;
  }

  if (!SetRenderState()) return FALSE;
  return TRUE;
}
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
      : TForm(Owner)
{
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Timer1Timer(TObject *Sender)
{
  HRESULT rval;

  Timer1->Tag += Timer1->Interval;

  // Tick the scene.
  ProgramData.FrameBol1
   ->SetPosition(ProgramData.FrameScene,
                  D3DVAL(ProgramData.Bol1X + Timer1->Tag/1000.0), 0.0, D3DVAL(15));
  ProgramData.FrameBol2
   ->SetPosition(ProgramData.FrameScene,
                  D3DVAL(ProgramData.Bol2X + Timer1->Tag/1000.0), D3DVAL(0.0), D3DVAL(15));

  // Clear the viewport.
  rval = ProgramData.ViewPort->Clear();
  if (rval != D3DRM_OK) {
    // Error
  }

  // Render the scene to the viewport.
  rval = ProgramData.ViewPort->Render(ProgramData.FrameScene);
  if (rval != D3DRM_OK) {
    // Error
  }

  // Update the window.
  rval = ProgramData.Device->Update();
  if (rval != D3DRM_OK) {
    // Error
  }
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
  // Initialise non-3D program data .........................................
  // Set bols position
  ProgramData.Bol1X = StrToInt(EditBol1PosX->Text);
  ProgramData.Bol2X = StrToInt(EditBol2PosX->Text);
  ProgramData.Org1X = ProgramData.Bol1X;
  ProgramData.Org2X = ProgramData.Bol2X;
  ProgramData.Mass1 = StrToInt(EditBol1Mass->Text);
  ProgramData.Mass2 = StrToInt(EditBol2Mass->Text);
  ProgramData.Charge1 = StrToInt(EditCharge1->Text);
  ProgramData.Charge2 = StrToInt(EditCharge2->Text);
  ProgramData.ChargeMid = (ProgramData.Charge1*ProgramData.Bol1X + ProgramData.Charge2*ProgramData.Bol2X)
                          / (ProgramData.Charge1 + ProgramData.Charge2);
  ProgramData.Grav = StrToInt(EditGravitationBase->Text)*pow(10, StrToInt(EditGravitationExponent->Text));
  ProgramData.ForceMid
   = (ProgramData.Elec*(ProgramData.Charge2*ProgramData.Bol2X + ProgramData.Charge2*ProgramData.Bol2X) - ProgramData.Grav*(ProgramData.Mass1*ProgramData.Bol1X + ProgramData.Mass2*ProgramData.Bol2X))
     /(ProgramData.Elec*(ProgramData.Charge1 + ProgramData.Charge2) - ProgramData.Grav*(ProgramData.Mass1 + ProgramData.Mass2));
  ProgramData.RXOrg = abs(ProgramData.Bol2X - ProgramData.Bol1X);
  ProgramData.MassMid = (ProgramData.Mass1*ProgramData.Bol1X + ProgramData.Mass2*ProgramData.Bol2X)
                        / (ProgramData.Mass1 + ProgramData.Mass2);
  ProgramData.Precision = StrToInt(EditPrecision->Text);
  ProgramData.TimeScale = StrToInt(EditTimeScaleBase->Text)*pow(10, StrToInt(EditTimeScaleExponent->Text));
  //........................................................................

  // Initialize and run
  ProgramData.BPP = 16;
  if (!EnumDrivers(Handle)) {
    // Error
  }

  D3DRM = NULL;
  Direct3DRMCreate(&D3DRM);

  // Create the master scene frame and camera frame.
  D3DRM->CreateFrame(NULL, &ProgramData.FrameScene);
  D3DRM->CreateFrame(ProgramData.FrameScene, &ProgramData.FrameCamera);
  ProgramData.FrameCamera->SetPosition(ProgramData.FrameScene,
                                        D3DVAL(0.0), D3DVAL(0.0), D3DVAL(0.0));

  // Create a DirectDrawClipper object and associate the window with it.
  DirectDrawCreateClipper(0, &lpDDClipper, NULL);
  lpDDClipper->SetHWnd(0, Handle);

  // Create the D3DRM device by using the selected D3D driver.
  if (!CreateDevAndView(lpDDClipper, ProgramData.CurrDriver, ClientWidth, ClientHeight)) {
    // Fatal error 35
  }

  // Begin creating the Scene
  LPDIRECT3DRMFRAME LightFrame = NULL;

  LPDIRECT3DRMLIGHT Light1 = NULL;
  LPDIRECT3DRMLIGHT LightAmbient = NULL;
  LPDIRECT3DRMTEXTURE Texture = NULL;
  LPDIRECT3DRMWRAP Wrap = NULL;
  LPDIRECT3DRMMESHBUILDER MeshBuilder = NULL;
  LPDIRECT3DRMMESHBUILDER MeshBuilder2 = NULL;

  // Create Frames
  D3DRM->CreateFrame(ProgramData.FrameScene, &LightFrame);
  D3DRM->CreateFrame(ProgramData.FrameScene, &ProgramData.FrameBol1);
  D3DRM->CreateFrame(ProgramData.FrameScene, &ProgramData.FrameBol2);

  // Create Lights
  D3DRM->CreateLightRGB(D3DRMLIGHT_DIRECTIONAL, D3DVAL(0.9), D3DVAL(0.9), D3DVAL(0.9),
                         &Light1);
  LightFrame->AddLight(Light1);

  D3DRM->CreateLightRGB(D3DRMLIGHT_AMBIENT, D3DVAL(0.75), D3DVAL(0.75), D3DVAL(0.75),
                         &LightAmbient);
  ProgramData.FrameScene->AddLight(LightAmbient);

  // Set the positions
  LightFrame->SetPosition(ProgramData.FrameScene, D3DVAL(2), D3DVAL(0.0), D3DVAL(22));
  ProgramData.FrameCamera->SetPosition(ProgramData.FrameScene,
                                        D3DVAL(0.0), D3DVAL(0.0), D3DVAL(0.0));
  ProgramData.FrameCamera->SetOrientation(ProgramData.FrameScene,
                                           D3DVAL(0.0), D3DVAL(0.0), D3DVAL(1),
                                            D3DVAL(0.0), D3DVAL(1), D3DVAL(0.0));
  ProgramData.FrameBol1->SetOrientation(ProgramData.FrameScene,
                                         D3DVAL(0.0), D3DVAL(0.0), D3DVAL(1),
                                          D3DVAL(0.0), D3DVAL(1), D3DVAL(0.0));
  ProgramData.FrameBol1->SetRotation(ProgramData.FrameScene,
                                      D3DVAL(0.0), D3DVAL(0.1), D3DVAL(0.0), D3DVAL(0.05));
  ProgramData.FrameBol2->SetOrientation(ProgramData.FrameScene,
                                         D3DVAL(0.0), D3DVAL(0.0), D3DVAL(1),
                                          D3DVAL(0.0), D3DVAL(1), D3DVAL(0.0));
  ProgramData.FrameBol2->SetRotation(ProgramData.FrameScene,
                                      D3DVAL(0.0), D3DVAL(0.1), D3DVAL(0.0), D3DVAL(0.05));

  // Make the Mesh
  D3DRM->CreateMeshBuilder(&MeshBuilder);
  D3DRM->CreateMeshBuilder(&MeshBuilder2);
  MeshBuilder->Load("sphere0.x", NULL, D3DRMLOAD_FROMFILE, NULL, NULL);
  MeshBuilder2->Load("sphere0.x", NULL, D3DRMLOAD_FROMFILE, NULL, NULL);
  if (ProgramData.Charge1 > 0) {
    MeshBuilder->SetColorRGB(1, 0, 0);
  } else {
    MeshBuilder->SetColorRGB(0, 1, 0);
  }

  if (ProgramData.Charge2 > 0) {
    MeshBuilder2->SetColorRGB(1, 0, 0);
  } else {
    MeshBuilder2->SetColorRGB(0, 1, 0);
  }

  // Create the Texture
  D3DVALUE Miny, Maxy, Heighty;
  D3DRMBOX D3DRMBox;

  MeshBuilder->GetBox(&D3DRMBox);
  Maxy = D3DRMBox.max.y;
  Miny = D3DRMBox.min.y;
  Heighty = Maxy - Miny;

  D3DRM->CreateWrap(D3DRMWRAP_CYLINDER, NULL,
                     D3DVAL(0.0), D3DVAL(0.0), D3DVAL(0.0),
                      D3DVAL(0.0), D3DVAL(1.0), D3DVAL(0.0),
                       D3DVAL(0.0), D3DVAL(0.0), D3DVAL(1.0),
                        D3DVAL(0.0), D3DDivide(Miny, Heighty),
                         D3DVAL(1.0), D3DDivide(-D3DVAL(1.0), Heighty),
                          &Wrap);
  Wrap->Apply((LPDIRECT3DRMOBJECT) MeshBuilder);
  Wrap->Apply((LPDIRECT3DRMOBJECT) MeshBuilder2);

  // Add the Texture
  D3DRM->LoadTexture("tutor.bmp", &Texture);

     // If you need a color depth other than the default (16), call IDirect3DRMTexture::SetShades here.
  MeshBuilder->SetTexture(Texture);
  MeshBuilder2->SetTexture(Texture);

     // If you need to create a material (for example, to create a shiny surface), call CreateMaterial and SetMaterial here.

  // Welcome to the world, objects!
  MeshBuilder->Scale(ProgramData.Mass1/5.0, ProgramData.Mass1/5.0, ProgramData.Mass1/5.0);
  ProgramData.FrameBol1->AddVisual((LPDIRECT3DRMVISUAL) MeshBuilder);

  MeshBuilder2->Scale(ProgramData.Mass2/5.0, ProgramData.Mass2/5.0, ProgramData.Mass2/5.0);
  ProgramData.FrameBol2->AddVisual((LPDIRECT3DRMVISUAL) MeshBuilder2);

  // Release all
  LightFrame->Release();
  MeshBuilder->Release();
  MeshBuilder2->Release();
  Light1->Release();
  LightAmbient->Release();
  Texture->Release();
  Wrap->Release();

  // Activate the rendering loop
  Panel1->Visible = false;
  Timer1->Enabled = true;
}
//---------------------------------------------------------------------------
void __fastcall TForm1::FormDestroy(TObject *Sender)
{
  Timer1->Enabled = false;

  ProgramData.FrameScene->Release();
  ProgramData.FrameCamera->Release();
  ProgramData.ViewPort->Release();
  ProgramData.Device->Release();

  D3DRM->Release();
  lpDDClipper->Release();

  ProgramData.bQuit = true;
}
//---------------------------------------------------------------------------

0
 

Expert Comment

by:azar
Comment Utility
Without being able to get ALL of your code, it is tough to see anything obvious.   The code is quite simple and looks correct at first glance - it seems you most likely have a data error in your buttonclick methods data values.

ff you want, please send my the WHOLE project (you did not include the 'MainUnit' file included in the code above, etc.) zipped up and I'll debug it for you.  Give a written description of when the error occurs AND send the object files with the zipped MSVC++ project, C++/H files, etc.

I have a D3D book out, so I know this area well and I'd be happy to help  (I just joined this exchange, but it looks like a great resource/idea)

If you want to send the code, place a comment back with your E-mail and I'll send you a response there so you can E-mail to the address I send from
0
 
LVL 1

Author Comment

by:Odie
Comment Utility
OK, great - smathsoft@geocities.com
0
6 Surprising Benefits of Threat Intelligence

All sorts of threat intelligence is available on the web. Intelligence you can learn from, and use to anticipate and prepare for future attacks.

 

Accepted Solution

by:
Ant031898 earned 50 total points
Comment Utility
Add the following line:

_control87(MCW_EM,MCW_EM);

as the first line in the try block of your WinMain function and see if the problem goes away - worth a try.

i.e.

WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
{
      try
      {
            _control87(MCW_EM,MCW_EM);
                Application->Initialize();
                ...
                ...
0
 
LVL 1

Author Comment

by:Odie
Comment Utility
OK - I'm going to try it.

Could you tell me what it is?
Does this change the rounding mode?
(I once had a problem using arithmetic compression - it worked in c++ but not in pascal and it was all solved by just doing something (via assembler) with that control word, but I don't understand what exactly happened)
0
 
LVL 1

Author Comment

by:Odie
Comment Utility
Incredible - are we supposed to smell that?  Bloody M.
I found what it means now, but am I right when thinking that even when putting of the exception error messages, I might still get bad results?  Not only things that don't look right but maybe a sneaky bug showing up later?

Thanks anyway
0
 

Expert Comment

by:Ant031898
Comment Utility
That disables the floating point errors that are send by the win32 api, as far as I know.  If for example there is a discontinuity in the object you are drawing - this will filter it out.  I don't think it fixes the problem, but at least it hides it.  Well if you can't fix - f*ck it.
cheers
0

Featured Post

IT, Stop Being Called Into Every Meeting

Highfive is so simple that setting up every meeting room takes just minutes and every employee will be able to start or join a call from any room with ease. Never be called into a meeting just to get it started again. This is how video conferencing should work!

Join & Write a Comment

In days of old, returning something by value from a function in C++ was necessarily avoided because it would, invariably, involve one or even two copies of the object being created and potentially costly calls to a copy-constructor and destructor. A…
Go is an acronym of golang, is a programming language developed Google in 2007. Go is a new language that is mostly in the C family, with significant input from Pascal/Modula/Oberon family. Hence Go arisen as low-level language with fast compilation…
The goal of the tutorial is to teach the user how to use functions in C++. The video will cover how to define functions, how to call functions and how to create functions prototypes. Microsoft Visual C++ 2010 Express will be used as a text editor an…
The viewer will learn how to user default arguments when defining functions. This method of defining functions will be contrasted with the non-default-argument of defining functions.

763 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

12 Experts available now in Live!

Get 1:1 Help Now