/*
 * 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: imgMirror.c,v 1.10 2008/11/09 14:37:04 wes Exp $
 * $Revision: 1.10 $
 * $Name: v180-alpha-01 $
 * $Log: imgMirror.c,v $
 * Revision 1.10  2008/11/09 14:37:04  wes
 * Update dates to 2008
 *
 * Revision 1.9  2006/08/08 03:49:21  wes
 * Updates to reflect ergonomic changes to rmaux
 *
 * Revision 1.8  2005/07/04 18:12:48  wes
 * Fix w32 compile problems.
 *
 * Revision 1.7  2005/06/08 17:56:21  wes
 * Code cleanup to eliminate compiler warnings.
 *
 * Revision 1.6  2003/04/13 18:13:23  wes
 * Updated copyright dates.
 *
 * Revision 1.5  2003/01/27 05:07:07  wes
 * Changes to RMpipe initialization sequence APIs. Tested for GLX, but not WGL.
 *
 * 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/09/22 17:31:43  wes
 * Added code to delete RMimage objects after they've been loaded
 * in as sprites.
 *
 * Revision 1.2  2002/06/17 00:37:27  wes
 * Updated copyright line.
 *
 * Revision 1.1  2001/10/15 00:23:34  wes
 * Initial entry.
 *
 */

/*
 * usage: imgMirror [-w imgWidth] [-h imgHeight]
 */

#include <stdio.h>
#ifndef RM_WIN
#include <unistd.h>
#endif
#include <rm/rm.h>   
#include <rm/rmaux.h>
#include <rm/rmi.h>
#include "procmode.h"

static RMpipe *myPipe=NULL;

#define DEFAULT_IMAGE_WIDTH 800
#define DEFAULT_IMAGE_HEIGHT 700

void
create2DCamera(RMpipe *p,
	       RMnode *root)
{
    RMcamera2D *c = rmCamera2DNew();
    float viewExtents[] = {-1.1, -1.1, 1.1, 1.1};
    float viewPort[] = {0.0,  0.0, 1.0, 1.0};
    RMcolor4D bgColor = {.3F, .3F, .3F, 1.0F};
    int winW, winH;

    rmPipeGetWindowSize(p, &winW, &winH);
    rmNodeSetSceneBackgroundColor(root, &bgColor);
    
    rmCamera2DSetAspectRatio(c, (float)winW/(float)winH); 
    rmCamera2DSetExtents(c, viewExtents[0], viewExtents[1], viewExtents[2], viewExtents[3]);

    rmNodeSetSceneCamera2D(root, c);
    rmNodeSetSceneViewport(root, viewPort);

    rmCamera2DDelete(c);
}

void
createObjects(RMnode *localRoot,
	      RMimage *src)
{
    RMnode *upperLeft, *lowerLeft, *upperRight, *lowerRight;
    RMprimitive *p;
    RMvertex2D v00={-1.0, 0.2};
    RMvertex2D v01={-1.0, -1.0};
    RMvertex2D v10={0.2, 0.2};
    RMvertex2D v11={0.2, -1.0};
    RMimage *upperLeftImage=NULL, *lowerLeftImage=NULL;
    RMimage *upperRightImage=NULL, *lowerRightImage=NULL;

    upperLeft = rmNodeNew("upperLeft", RM_RENDERPASS_2D, RM_RENDERPASS_ALL);
    lowerLeft = rmNodeNew("lowerLeft", RM_RENDERPASS_2D, RM_RENDERPASS_ALL);
    upperRight = rmNodeNew("upperRight", RM_RENDERPASS_2D, RM_RENDERPASS_ALL);
    lowerRight = rmNodeNew("lowerRight", RM_RENDERPASS_2D, RM_RENDERPASS_ALL);

    upperLeftImage = rmImageDup(src);

    p = rmPrimitiveNew(RM_SPRITE);
    rmPrimitiveSetVertex2D(p, 1, &v00, RM_COPY_DATA, NULL);
    rmPrimitiveSetSprites(p, 1, &upperLeftImage);
    
    rmNodeAddPrimitive(upperLeft, p);
    rmNodeAddChild(localRoot, upperLeft);

    /* do lower left image - mirror about vertical axis */
    lowerLeftImage = rmImageDup(src);
    rmImageMirror(lowerLeftImage, RM_IMAGE_MIRROR_HEIGHT); 
    
    p = rmPrimitiveNew(RM_SPRITE);
    rmPrimitiveSetVertex2D(p, 1, &v01, RM_COPY_DATA, NULL);
    rmPrimitiveSetSprites(p, 1, &lowerLeftImage);
    
    rmNodeAddPrimitive(lowerLeft, p);
    rmNodeAddChild(localRoot, lowerLeft);

    /* do upper right image - mirror about horizontal axis */
    upperRightImage = rmImageDup(src);
    rmImageMirror(upperRightImage, RM_IMAGE_MIRROR_WIDTH);
    
    p = rmPrimitiveNew(RM_SPRITE);
    rmPrimitiveSetVertex2D(p, 1, &v10, RM_COPY_DATA, NULL);
    rmPrimitiveSetSprites(p, 1, &upperRightImage);

    rmNodeAddPrimitive(upperRight, p);
    rmNodeAddChild(localRoot, upperRight);

    /* lower right image - mirror about (1) horizontal, then (2) vertical */
    lowerRightImage = rmImageDup(src);
    rmImageMirror(lowerRightImage, RM_IMAGE_MIRROR_WIDTH);
    rmImageMirror(lowerRightImage, RM_IMAGE_MIRROR_HEIGHT);
    
    p = rmPrimitiveNew(RM_SPRITE);
    rmPrimitiveSetVertex2D(p, 1, &v11, RM_COPY_DATA, NULL);
    rmPrimitiveSetSprites(p, 1, &lowerRightImage);
    
    rmNodeAddPrimitive(lowerRight, p);
    rmNodeAddChild(localRoot, lowerRight);

    /* free up images */
    rmImageDelete(lowerRightImage);
    rmImageDelete(upperRightImage);
    rmImageDelete(lowerLeftImage);
    rmImageDelete(upperLeftImage);
}

void
myInitFunc(RMpipe *p,
	   RMnode *n,
	   void *usrData)
{
    char fname[]={"data/doghead.jpg"};
    RMimage *srcImage = rmiReadJPEG(fname);
    RMimage *useImage = rmImageNew(2, 256, 256, 1, RM_IMAGE_RGB, RM_UNSIGNED_BYTE, RM_COPY_DATA);
    RMnode *localRoot = rmNodeNew("localRoot", RM_RENDERPASS_2D, RM_RENDERPASS_OPAQUE);

    if (srcImage == NULL)
    {
	rmError(" myInitFunc() error reading source image. ");
	exit(-1);
    }
    else
    {
	int w,h;
	rmImageGetImageSize(srcImage, NULL, &w, &h, NULL, NULL, NULL);
	printf(" w/h of src image are %d, %d \n", w,h);
	rmImageMirror(srcImage, RM_IMAGE_MIRROR_HEIGHT);
	rmImageResize(srcImage, useImage, RM_SOFTWARE, p);
    }

    /* create the 2D camera for the view model */
    create2DCamera(p, localRoot);

    /* populate the scene graph with drawable stuff */
    createObjects(localRoot, useImage);

    /* free up images */
    rmImageDelete(srcImage);
    rmImageDelete(useImage);

    rmNodeAddChild(n, localRoot);

    rmFrame(p, n);
}

void
usage(char *s)
{
    printf("usage: %s [-w imgWidth] [-h imgHeight] \n",s);
}

void
parseArgs(int ac,
	  char *av[],
	  int *imgWidth,
	  int *imgHeight)
{
    int i;

    i = 1;
    while (i < ac)
    {
	if (strcmp(av[i],"-w") == 0)
	{
	    i++;
	    ac--;
	    sscanf(av[i],"%d", imgWidth);
	}
	else if (strcmp(av[i],"-h") == 0)
	{
	    i++;
	    ac--;
	    sscanf(av[i],"%d", imgHeight);
	}
	else
	{
	    usage(av[0]);
	    exit(-1);
	}
	i++;
    }
}

#ifdef RM_WIN
int WINAPI WinMain (HINSTANCE hInstance,
		    HINSTANCE hPrevInstance,
                    LPSTR lpszCmdLine, int nCmdShow)
{
    MSG      msg; 
    HWND     hWnd; 
    void *fptr;
    
    int imgWidth, imgHeight;
    RMenum processingMode = DEFAULT_PROCESSING_MODE; /* in procmode.h */
    RMenum targetPlatform = RM_PIPE_WGL;

    imgWidth = DEFAULT_IMAGE_WIDTH;
    imgHeight = DEFAULT_IMAGE_HEIGHT;
    
    parseArgs(__argc, __argv, &imgWidth, &imgHeight); 
    
#else  /* assume RM_X */
int
main(int argc,
     char *argv[])
{
    void *msg;			/* needed for rmauxEventLoop
				 win32/unix API consistency */
    int imgWidth, imgHeight;
    RMenum processingMode = DEFAULT_PROCESSING_MODE; /* in procmode.h */
    RMenum targetPlatform = RM_PIPE_GLX;

    imgWidth = DEFAULT_IMAGE_WIDTH;
    imgHeight = DEFAULT_IMAGE_HEIGHT;
    
    parseArgs(argc, argv, &imgWidth, &imgHeight); 
#endif

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

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

#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(myPipe,
			       NULL, /* no parent window */
			       20,20,imgWidth,imgHeight,"RM for Windows",
			       hInstance,fptr);
	if (hWnd == 0)
	  exit(-1);

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

	w = rmauxCreateXWindow(myPipe,
			       (Window)NULL, /* parent window */
			       0,0,imgWidth,imgHeight,
			       "RM for X-Windows","RM for X-Windows",RM_TRUE);

	/* 
	 * assign the window to the rendering pipe.
	 */
	rmPipeSetWindow(myPipe,w,imgWidth,imgHeight);
    }
#endif

    /* 
     * X-ism: once the window is created and assigned to the 
     * rendering pipe, rmPipeMakeCurrent 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(myPipe);	

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

    rmFinish();

    return(1);
}
   
/* EOF */ 
