1/*
2 * Copyright (c) 1991, 1992, 1993 Silicon Graphics, Inc.
3 *
4 * Permission to use, copy, modify, distribute, and sell this software and
5 * its documentation for any purpose is hereby granted without fee, provided
6 * that (i) the above copyright notices and this permission notice appear in
7 * all copies of the software and related documentation, and (ii) the name of
8 * Silicon Graphics may not be used in any advertising or
9 * publicity relating to the software without the specific, prior written
10 * permission of Silicon Graphics.
11 *
12 * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF
13 * ANY KIND,
14 * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
15 * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
16 *
17 * IN NO EVENT SHALL SILICON GRAPHICS BE LIABLE FOR
18 * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
19 * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
20 * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
21 * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
22 * OF THIS SOFTWARE.
23 */
24
25#include <stdio.h>
26#include <stdlib.h>
27#include <string.h>
28#include <math.h>
29#include "glut_wrap.h"
30
31
32#define STEPCOUNT 40
33#define FALSE 0
34#define TRUE 1
35#define MAX(a, b) (((a) > (b)) ? (a) : (b))
36#define MIN(a, b) (((a) < (b)) ? (a) : (b))
37
38
39enum {
40    OP_NOOP = 0,
41    OP_STRETCH,
42    OP_DRAWPOINT,
43    OP_DRAWIMAGE
44};
45
46
47typedef struct _cRec {
48    float x, y;
49} cRec;
50
51typedef struct _vertexRec {
52    float x, y;
53    float dX, dY;
54    float tX, tY;
55} vertexRec;
56
57
58#include "loadppm.c"
59
60GLenum doubleBuffer;
61int imageSizeX, imageSizeY;
62char *fileName = 0;
63PPMImage *image;
64cRec cList[50];
65vertexRec vList[5];
66int cCount, cIndex[2], cStep;
67GLenum op = OP_NOOP;
68
69
70static void DrawImage(void)
71{
72
73    glRasterPos2i(0, 0);
74    glDrawPixels(image->sizeX, image->sizeY, GL_RGB, GL_UNSIGNED_BYTE,
75		 image->data);
76
77    glFlush();
78    if (doubleBuffer) {
79	glutSwapBuffers();
80    }
81
82    glRasterPos2i(0, 0);
83    glDrawPixels(image->sizeX, image->sizeY, GL_RGB, GL_UNSIGNED_BYTE,
84		 image->data);
85}
86
87static void DrawPoint(void)
88{
89    int i;
90
91    glColor3f(1.0, 0.0, 1.0);
92    glPointSize(3.0);
93    glBegin(GL_POINTS);
94	for (i = 0; i < cCount; i++) {
95	    glVertex2f(cList[i].x, cList[i].y);
96	}
97    glEnd();
98
99    glFlush();
100    if (doubleBuffer) {
101	glutSwapBuffers();
102    }
103}
104
105static void InitVList(void)
106{
107
108    vList[0].x = 0.0;
109    vList[0].y = 0.0;
110    vList[0].dX = 0.0;
111    vList[0].dY = 0.0;
112    vList[0].tX = 0.0;
113    vList[0].tY = 0.0;
114
115    vList[1].x = (float)imageSizeX;
116    vList[1].y = 0.0;
117    vList[1].dX = 0.0;
118    vList[1].dY = 0.0;
119    vList[1].tX = 1.0;
120    vList[1].tY = 0.0;
121
122    vList[2].x = (float)imageSizeX;
123    vList[2].y = (float)imageSizeY;
124    vList[2].dX = 0.0;
125    vList[2].dY = 0.0;
126    vList[2].tX = 1.0;
127    vList[2].tY = 1.0;
128
129    vList[3].x = 0.0;
130    vList[3].y = (float)imageSizeY;
131    vList[3].dX = 0.0;
132    vList[3].dY = 0.0;
133    vList[3].tX = 0.0;
134    vList[3].tY = 1.0;
135
136    vList[4].x = cList[0].x;
137    vList[4].y = cList[0].y;
138    vList[4].dX = (cList[1].x - cList[0].x) / STEPCOUNT;
139    vList[4].dY = (cList[1].y - cList[0].y) / STEPCOUNT;
140    vList[4].tX = cList[0].x / (float)imageSizeX;
141    vList[4].tY = cList[0].y / (float)imageSizeY;
142}
143
144static void ScaleImage(int sizeX, int sizeY)
145{
146    GLubyte *buf;
147
148    buf = (GLubyte *)malloc(3*sizeX*sizeY);
149    gluScaleImage(GL_RGB, image->sizeX, image->sizeY, GL_UNSIGNED_BYTE,
150                  image->data, sizeX, sizeY, GL_UNSIGNED_BYTE, buf);
151    free(image->data);
152    image->data = buf;
153    image->sizeX = sizeX;
154    image->sizeY = sizeY;
155}
156
157static void SetPoint(int x, int y)
158{
159
160    cList[cCount].x = (float)x;
161    cList[cCount].y = (float)y;
162    cCount++;
163}
164
165static void Stretch(void)
166{
167
168    glBegin(GL_TRIANGLES);
169	glTexCoord2f(vList[0].tX, vList[0].tY);
170	glVertex2f(vList[0].x, vList[0].y);
171	glTexCoord2f(vList[1].tX, vList[1].tY);
172	glVertex2f(vList[1].x, vList[1].y);
173	glTexCoord2f(vList[4].tX, vList[4].tY);
174	glVertex2f(vList[4].x, vList[4].y);
175    glEnd();
176
177    glBegin(GL_TRIANGLES);
178	glTexCoord2f(vList[1].tX, vList[1].tY);
179	glVertex2f(vList[1].x, vList[1].y);
180	glTexCoord2f(vList[2].tX, vList[2].tY);
181	glVertex2f(vList[2].x, vList[2].y);
182	glTexCoord2f(vList[4].tX, vList[4].tY);
183	glVertex2f(vList[4].x, vList[4].y);
184    glEnd();
185
186    glBegin(GL_TRIANGLES);
187	glTexCoord2f(vList[2].tX, vList[2].tY);
188	glVertex2f(vList[2].x, vList[2].y);
189	glTexCoord2f(vList[3].tX, vList[3].tY);
190	glVertex2f(vList[3].x, vList[3].y);
191	glTexCoord2f(vList[4].tX, vList[4].tY);
192	glVertex2f(vList[4].x, vList[4].y);
193    glEnd();
194
195    glBegin(GL_TRIANGLES);
196	glTexCoord2f(vList[3].tX, vList[3].tY);
197	glVertex2f(vList[3].x, vList[3].y);
198	glTexCoord2f(vList[0].tX, vList[0].tY);
199	glVertex2f(vList[0].x, vList[0].y);
200	glTexCoord2f(vList[4].tX, vList[4].tY);
201	glVertex2f(vList[4].x, vList[4].y);
202    glEnd();
203
204    glFlush();
205    if (doubleBuffer) {
206	glutSwapBuffers();
207    }
208
209    if (++cStep < STEPCOUNT) {
210	vList[4].x += vList[4].dX;
211	vList[4].y += vList[4].dY;
212    } else {
213	cIndex[0] = cIndex[1];
214	cIndex[1] = cIndex[1] + 1;
215	if (cIndex[1] == cCount) {
216	    cIndex[1] = 0;
217	}
218	vList[4].dX = (cList[cIndex[1]].x - cList[cIndex[0]].x) / STEPCOUNT;
219	vList[4].dY = (cList[cIndex[1]].y - cList[cIndex[0]].y) / STEPCOUNT;
220	cStep = 0;
221    }
222}
223
224static void Key(unsigned char key, int x, int y)
225{
226
227    switch (key) {
228      case 27:
229	free(image->data);
230        exit(1);
231      case 32:
232	if (cCount > 1) {
233	    InitVList();
234	    cIndex[0] = 0;
235	    cIndex[1] = 1;
236	    cStep = 0;
237	    glEnable(GL_TEXTURE_2D);
238	    op = OP_STRETCH;
239	}
240	break;
241      default:
242	return;
243    }
244
245    glutPostRedisplay();
246}
247
248static void Mouse(int button, int state, int mouseX, int mouseY)
249{
250
251    if (state != GLUT_DOWN)
252	return;
253
254    if (op == OP_STRETCH) {
255	glDisable(GL_TEXTURE_2D);
256	cCount = 0;
257	op = OP_DRAWIMAGE;
258    } else {
259	SetPoint(mouseX, imageSizeY-mouseY);
260	op = OP_DRAWPOINT;
261    }
262
263    glutPostRedisplay();
264}
265
266static void Animate(void)
267{
268    static double t0 = -1.;
269    double t, dt;
270    t = glutGet(GLUT_ELAPSED_TIME) / 1000.;
271    if (t0 < 0.)
272       t0 = t;
273    dt = t - t0;
274
275    if (dt < 1./60.)
276        return;
277
278    t0 = t;
279
280    switch (op) {
281      case OP_STRETCH:
282	Stretch();
283	break;
284      case OP_DRAWPOINT:
285	DrawPoint();
286	break;
287      case OP_DRAWIMAGE:
288	DrawImage();
289	break;
290      default:
291        break;
292    }
293}
294
295static GLenum Args(int argc, char **argv)
296{
297    GLint i;
298
299    doubleBuffer = GL_TRUE;
300
301    for (i = 1; i < argc; i++) {
302	if (strcmp(argv[i], "-sb") == 0) {
303	    doubleBuffer = GL_FALSE;
304	} else if (strcmp(argv[i], "-db") == 0) {
305	    doubleBuffer = GL_TRUE;
306	} else if (strcmp(argv[i], "-f") == 0) {
307	    if (i+1 >= argc || argv[i+1][0] == '-') {
308		printf("-f (No file name).\n");
309		return GL_FALSE;
310	    } else {
311		fileName = argv[++i];
312	    }
313	} else {
314	    printf("%s (Bad option).\n", argv[i]);
315	    return GL_FALSE;
316	}
317    }
318    return GL_TRUE;
319}
320
321#if !defined(GLUTCALLBACK)
322#define GLUTCALLBACK
323#endif
324
325static void GLUTCALLBACK glut_post_redisplay_p(void)
326{
327      glutPostRedisplay();
328}
329
330int main(int argc, char **argv)
331{
332    GLenum type;
333
334    glutInit(&argc, argv);
335
336    if (Args(argc, argv) == GL_FALSE) {
337	exit(1);
338    }
339
340    if (fileName == 0) {
341	printf("No image file.\n");
342	exit(1);
343    }
344
345    image = LoadPPM(fileName);
346
347    /* changed powf and logf to pow and log -Brian */
348    imageSizeX = (int)pow(2.0, (float)((int)(log(image->sizeX)/log(2.0))));
349    imageSizeY = (int)pow(2.0, (float)((int)(log(image->sizeY)/log(2.0))));
350
351    glutInitWindowPosition(0, 0); glutInitWindowSize( imageSizeX, imageSizeY);
352
353    type = GLUT_RGB;
354    type |= (doubleBuffer) ? GLUT_DOUBLE : GLUT_SINGLE;
355    glutInitDisplayMode(type);
356
357    if (glutCreateWindow("Stretch") == GL_FALSE) {
358        exit(1);
359    }
360
361    glViewport(0, 0, imageSizeX, imageSizeY);
362    gluOrtho2D(0, imageSizeX, 0, imageSizeY);
363    glClearColor(0.0, 0.0, 0.0, 0.0);
364
365    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
366    glPixelStorei(GL_PACK_ALIGNMENT, 1);
367
368    ScaleImage(imageSizeX, imageSizeY);
369
370    glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
371    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
372    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
373    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
374    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
375    glTexImage2D(GL_TEXTURE_2D, 0, 3, image->sizeX, image->sizeY, 0,
376                 GL_RGB, GL_UNSIGNED_BYTE, (unsigned char *)image->data);
377
378    cCount = 0;
379    cIndex[0] = 0;
380    cIndex[1] = 0;
381    cStep = 0;
382    op = OP_DRAWIMAGE;
383
384    glutKeyboardFunc(Key);
385    glutMouseFunc(Mouse);
386    glutDisplayFunc(Animate);
387    glutIdleFunc(glut_post_redisplay_p);
388    glutMainLoop();
389	return 0;
390}
391