/*
 * Copyright (C) 2001-2008, R3vis Corporation.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA,
 * or visit http://www.gnu.org/copyleft/gpl.html.
 *
 * Contributor(s):
 *   Wes Bethel, R3vis Corporation, Marin County, California
 *
 * The OpenRM project is located at http://openrm.sourceforge.net/.
 */
/*
 * $Id: markers2d.c,v 1.10 2008/11/09 14:37:04 wes Exp $
 * $Revision: 1.10 $
 * $Name: v180-alpha-01 $
 * $Log: markers2d.c,v $
 * Revision 1.10  2008/11/09 14:37:04  wes
 * Update dates to 2008
 *
 * Revision 1.9  2007/07/22 17:37:47  wes
 * Added usrData and usrCallback parameters to all rmv routines
 *
 * Revision 1.8  2006/08/08 03:49:21  wes
 * Updates to reflect ergonomic changes to rmaux
 *
 * Revision 1.7  2005/06/08 17:24:27  wes
 * Code cleanup to eliminate compiler warnings.
 *
 * Revision 1.6  2005/05/16 01:33:07  wes
 * Major overhaul - demo now operational.
 *
 * Revision 1.5  2003/04/13 18:13:23  wes
 * Updated copyright dates.
 *
 * Revision 1.4  2003/01/16 22:22:45  wes
 * Updated all source files to reflect new organization of header files: all
 * headers that were formerly located in include/rmaux, include/rmv and
 * include/rmi are now located in include/rm.
 *
 * Revision 1.3  2002/06/17 00:39:40  wes
 * Updated copyright line.
 *
 * Revision 1.2  2001/07/15 22:33:19  wes
 * Added rmPipeDelete to the end of all demo progs. For those that use
 * an initfunc, added a new RMnode * parm (which is unused, except for rm2screen).
 *
 * Revision 1.1  2001/06/03 17:54:06  wes
 * Initial entry. This program is currently non-operational pending some
 * work inside OpenRM that will separate access to 2d geometric markers from
 * the RMV library.
 *
 *
 */

/*
 * June 3, 2001 - this program is not yet operational. Some additional
 * work is needed to separate 2d geometric markers from the RMV library.
 * wes
 */

#include <rm/rm.h>
#include <rm/rmv.h>
#include <rm/rmaux.h>
#include "procmode.h"

static RMnode *MyRoot;
int img_width=800,img_height=480;

typedef struct
{
    RMvertex2D p;
    char string[54];
} labelStruct;

#define CTEXT  0.0F
#define CZERO  0.1F
#define CONE   0.2F
#define CTWO   0.3F
#define CTHREE 0.4F
#define CFOUR  0.5F
#define CFIVE  0.6F
#define CSIX   0.7F
#define CSEVEN 0.8F

#define HHW 0.05
/*#define HHW 0.05 */

#define NUM_COLUMN_LABELS 1
#define NUM_ROW_LABELS    8

labelStruct columnLabels[NUM_COLUMN_LABELS] =
{
    {
	{CZERO-1.8*HHW, 1.F}, "Markers"
    }
};

labelStruct rowLabels[NUM_ROW_LABELS] =
{
    {
	{CTEXT-1.8*HHW, CZERO}, "RMV_2DMARKER_SQUARE"
    },
    {
	{CTEXT-1.8*HHW, CONE}, "RMV_2DMARKER_CROSS"
    },
    {
	{CTEXT-1.8*HHW, CTWO}, "RMV_2DMARKER_X"
    },
    {
	{CTEXT-1.8*HHW, CTHREE}, "RMV_2DMARKER_NORTHTRIANGLE"
    },
    {
	{CTEXT-1.8*HHW, CFOUR}, "RMV_2DMARKER_BOWTIE"
    },
    {
	{CTEXT-1.8*HHW, CFIVE}, "RMV_2DMARKER_SOUTHTRIANGLE"
    },
    {
	{CTEXT-1.8*HHW, CSIX}, "RMV_2DMARKER_DIAMOND"
    },
    {
	{CTEXT-1.8*HHW, CSEVEN}, "RMV_2DMARKER_NORTHTRIANGLE_FILLED"
    }
};

#define NUM_MARKERS 8

RMenum markerTypes[NUM_MARKERS] =
{
    RMV_2DMARKER_SQUARE,
    RMV_2DMARKER_CROSS,
    RMV_2DMARKER_X,
    RMV_2DMARKER_NORTHTRIANGLE,
    RMV_2DMARKER_BOWTIE,
    RMV_2DMARKER_SOUTHTRIANGLE,
    RMV_2DMARKER_DIAMOND,
    RMV_2DMARKER_NORTHTRIANGLE_FILLED
};

float markerXCoords[NUM_MARKERS] =
{
    CZERO, CONE, CTWO, CTHREE, CFOUR, CFIVE, CSIX, CSEVEN
};
float markerYCoords[NUM_MARKERS] =
{
    CZERO, CONE, CTWO, CTHREE, CFOUR, CFIVE, CSIX, CSEVEN
};

#define NUM_SCALES 6
float markerScale[NUM_SCALES] =
{
    0.01, 0.02, 0.04, 0.06, 0.08, 0.1
};

void
my_set_scene(RMnode *addTo)
{
    RMcamera2D *c = rmCamera2DNew();

    rmDefaultCamera2D(c);	/* assign it some default values. */

    /* change the default scene camera from (0,0) to (1,1) */
    rmCamera2DSetExtents(c, -0.5F, -0.2F, 1.25F, 1.2F);
    
    rmCamera2DSetExtents(c, -0.5F, -0.2F, 1.25F, 1.2F);

    /* add the camera to "my root's" scene parms. */
    rmNodeSetSceneCamera2D(addTo,c);
}

float
myDataFunc(int i,
	   void *usrData)
{
    /* foil compiler warning */
    i = 0;
    
    return(0.0F);
}

static RMvertex2D currentGridPoint;

RMvertex2D
myGridFunc(int i,
	   void *usrData)
{
    /* foil compiler warning */
    i = 0;
    
    return currentGridPoint;
}

void
my_build_objs(void)
{
    int rows, cols;
    RMprimitive *tlist;
    RMnode *textRoot;
    RMnode *textNode;
    RMnode *markersRoot;

    MyRoot = rmNodeNew("MyRoot", RM_RENDERPASS_2D, RM_RENDERPASS_OPAQUE);
    textRoot = rmNodeNew("textRoot",RM_RENDERPASS_2D, RM_RENDERPASS_OPAQUE);
    markersRoot = rmNodeNew("markersRoot",RM_RENDERPASS_2D,
			    RM_RENDERPASS_OPAQUE);
    rmNodeAddChild(rmRootNode(),MyRoot); 
    rmNodeAddChild(MyRoot,textRoot);
    rmNodeAddChild(MyRoot,markersRoot);

    for (rows=0;rows < NUM_MARKERS; rows++)
    {
	int cols;
	currentGridPoint.y = markerYCoords[rows];

	for (cols=0; cols < NUM_SCALES; cols++)
	{
	    currentGridPoint.x = markerXCoords[cols];
	    rmvI2ScatterGeom(myGridFunc, NULL,
			     myDataFunc, NULL,
			     NULL, NULL,
			     NULL,
			     RMV_XAXIS_OFFSET, 1, markerScale[cols],
			     RMV_SCALE_ABSOLUTE, markerTypes[rows], markersRoot);
	}
    }

    /*
     * for all the column headers, we have to set node-level text properties
     * to declare horizontal centering for justification, and use a smaller-
     * than-default font size.
     */

    for (cols=0; cols < NUM_SCALES; cols++) 
    {
	char name[32];
	char *strings[1];
	RMtextProps *tp;
	RMcolor4D c={1.0F, 1.0F, 0.5F, 1.0F};
	RMvertex2D textVertex;

	sprintf(name,"text-%d",cols);
	
	textNode = rmNodeNew(name,RM_RENDERPASS_2D,RM_RENDERPASS_OPAQUE);
	rmNodeSetUnlitColor(textNode, &c);
	tlist = rmPrimitiveNew(RM_TEXT);
	rmNodeAddPrimitive(textNode, tlist);
	rmNodeAddChild(textRoot, textNode);

	textVertex.x = markerXCoords[cols];
	textVertex.y = -0.1;
	rmPrimitiveSetVertex2D(tlist,1,
			       &textVertex,
			       RM_COPY_DATA, /* let RM manage this data */
			       NULL); /* don't need a freefunc for RM_COPY_DATA */

	sprintf(name, "%g", markerScale[cols]);
	strings[0] = name;
	
	rmPrimitiveSetText(tlist,1,strings);

	tp = rmTextPropsNew();
	rmTextPropsSetAttribs(tp,
			      RM_FONT_SANS, /* font family */
			      RM_FONT_M, /* size */
			      RM_FALSE,	/* embolden? */
			      RM_FALSE,	/* italicize? */
			      RM_CENTER, /* horiz justification */
			      RM_BOTTOM); /* vertical justification */
	
	rmNodeSetSceneTextProps(textNode, tp);
	rmTextPropsDelete(tp);
    }

    
    /*
     * for all the column headers, we have to set node-level text properties
     * to declare horizontal centering for justification, and use a smaller-
     * than-default font size.
     */
    for (rows=0; rows < NUM_MARKERS; rows++) 
    {
	char name[32];
	char *strings[1];
	RMtextProps *tp;
	RMcolor4D c={0.5F, 1.0F, 0.5F, 1.0F};

	sprintf(name,"text-%d",rows);
	
	textNode = rmNodeNew(name,RM_RENDERPASS_2D,RM_RENDERPASS_OPAQUE);
	rmNodeSetUnlitColor(textNode,&c);
	tlist = rmPrimitiveNew(RM_TEXT);
	rmNodeAddPrimitive(textNode, tlist);
	rmNodeAddChild(textRoot, textNode);
	
	rmPrimitiveSetVertex2D(tlist,1,
			       &(rowLabels[rows].p), /* pointer to stuff */
			       RM_COPY_DATA, /* let RM manage this data */
			       NULL); /* don't need a freefunc for RM_COPY_DATA */
	
	strings[0] = rowLabels[rows].string;
	rmPrimitiveSetText(tlist,1,strings);

	tp = rmTextPropsNew();
	rmTextPropsSetAttribs(tp,
			      RM_FONT_SANS, /* font family */
			      RM_FONT_XXS, /* size */
			      RM_FALSE,	/* embolden? */
			      RM_FALSE,	/* italicize? */
			      RM_RIGHT, /* horiz justification */
			      RM_BOTTOM); /* vertical justification */
	
	rmNodeSetSceneTextProps(textNode, tp);
	rmTextPropsDelete(tp);
    }
}

void
myinitfunc(RMpipe *p,
	   RMnode *n,
	   void *usrData)
{
    my_build_objs();
    my_set_scene(MyRoot);
    rmauxUI(n, p);

    /*
     * set handler to reset aspect ratio when the window is resized.
     */
    rmauxSetResizeFunc(p, MyRoot, rmauxDefaultResizeFunc);

    if (rmPipeProcessingModeIsMultithreaded(p) == RM_TRUE)
	rmFrame(p, n);
    
    rmFrame(p, n);
}

#ifdef RM_WIN
int WINAPI WinMain (HINSTANCE hInstance,
		    HINSTANCE hPrevInstance,
                    LPSTR lpszCmdLine, int nCmdShow)
{
    MSG      msg; 
    HWND     hWnd; 
    void *fptr;
    RMenum targetPlatform = RM_PIPE_WGL;
#else  /* assume RM_X */
int
main()
{
    void *msg;			/* needed for rmauxEventLoop
				 win32/unix API consistency */
    RMenum targetPlatform = RM_PIPE_GLX;
#endif
    RMpipe *pipe=NULL;
    RMenum processingMode = DEFAULT_PROCESSING_MODE; /* in procmode.h */

    /* 
     * first stage of RM initialization.
     */
    rmInit();

    /* 
     * create the rendering pipe. this step is required in both
     * Win32 and X.
     */
    pipe = rmPipeNew(targetPlatform);
    rmPipeSetProcessingMode(pipe, processingMode);

    /*
     * set the background clear property on the RMpipe
     */
    {
	RMcolor4D c = {0.1F, 0.1F, 0.2F, 1.0F};
	rmPipeSetSceneBackgroundColor(pipe, &c);
    }
    
#ifdef RM_WIN
    {
        /*
	 * Win32: when a window is created, we have to tell windows the
	 * name of the "WndProc," the procedure that gets called by
	 * windows with events (the event loop) (contrast to the X model 
	 * where the name of the event loop is not part of the window). 
	 * Since we're using RMaux, we know about the event handling 
	 * procedure named "rmauxWndProc" and we provide that here. 
	 */

        fptr = (void *)(rmauxWndProc);
	hWnd = rmauxCreateW32Window(pipe,
				    NULL, /* no parent window */
				    20,20,img_width,img_height,
				    "OpenRM - 2D Markers",
				    hInstance,fptr);
	if (hWnd == 0)
	  exit(-1);

	/* 
	 * assign the new window handle to the rendering pipe.
	 */
	rmPipeSetWindow(pipe,hWnd, img_width, img_height);
    }
#endif
    
#ifdef RM_X
    {
	Window w;

	w = rmauxCreateXWindow(pipe,
			       (Window)NULL, /* parent window */
			       0,0,img_width,img_height,
			       "OpenRM - 2D Markers","OpenRM",1);
	/* 
	 * assign the window to the rendering pipe.
	 */
	rmPipeSetWindow(pipe,w,img_width,img_height);
    }
#endif
    /* 
     * specify the name of the "init" function. the "init" function is
     * mandatory in the Win32 world, and optional in the X world. 
     *
     * in Win32, we don't want to call RM services until OpenGL is
     * ready. we can be assured of readiness by using an init function
     * with RMaux. 
     *
     * in X, at this point, the window is mapped and OpenGL is ready,
     * and we could call our init function directly.
     */

    rmauxSetInitCallbackFunc(myinitfunc, NULL); 

    /* 
     * X-ism: once the window is created and assigned to the 
     * rendering pipe, rmUsePipe makes the OpenGL rendering context
     * current for the pipe+window combination. 
     *
     * this step is required for X. in these demo programs, it is not 
     * strictly required by Win32, as the newly created context is made
     * current as part of the OpenGL initialization sequence.
     */
    rmPipeMakeCurrent(pipe);	

    /*
     * set key handler function so this prog will exit on "q" key
     */
    rmauxSetKeypressCallbackFunc(rmauxDefaultKeyFunc, NULL);
    
    rmauxEventLoop(pipe,rmRootNode(), &msg);

    rmPipeDelete(pipe);
    rmFinish();

#ifdef RM_WIN
    return( msg.wParam );
#else
    return(1);
#endif
}
/* EOF */ 
