Solved

DirectX floating point errors

Posted on 1998-03-14
8
481 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
ID: 1183464
Pls send some code!!!
0
 
LVL 1

Author Comment

by:Odie
ID: 1183465
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
ID: 1183466
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
Courses: Start Training Online With Pros, Today

Brush up on the basics or master the advanced techniques required to earn essential industry certifications, with Courses. Enroll in a course and start learning today. Training topics range from Android App Dev to the Xen Virtualization Platform.

 
LVL 1

Author Comment

by:Odie
ID: 1183467
OK, great - smathsoft@geocities.com
0
 

Accepted Solution

by:
Ant031898 earned 50 total points
ID: 1183468
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
ID: 1183469
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
ID: 1183470
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
ID: 1183471
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

Live: Real-Time Solutions, Start Here

Receive instant 1:1 support from technology experts, using our real-time conversation and whiteboard interface. Your first 5 minutes are always free.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

Title # Comments Views Activity
c++ how to tell if the progra is ctl or mfc atl ect 6 76
how to convert c++ code to Android App 3 95
C language IDE – Compilers installation 14 71
Getting IP address 8 77
Unlike C#, C++ doesn't have native support for sealing classes (so they cannot be sub-classed). At the cost of a virtual base class pointer it is possible to implement a pseudo sealing mechanism The trick is to virtually inherit from a base class…
Introduction This article is the first in a series of articles about the C/C++ Visual Studio Express debugger.  It provides a quick start guide in using the debugger. Part 2 focuses on additional topics in breakpoints.  Lastly, Part 3 focuses on th…
The viewer will learn how to pass data into a function in C++. This is one step further in using functions. Instead of only printing text onto the console, the function will be able to perform calculations with argumentents given by the user.
The viewer will be introduced to the technique of using vectors in C++. The video will cover how to define a vector, store values in the vector and retrieve data from the values stored in the vector.

776 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