Compare commits

...

8 Commits

Author SHA1 Message Date
Luke Benstead
46e1a9bcc5 Start cleaning up w handling 2018-06-26 08:31:31 +01:00
Luke Benstead
09789c9adc Make sure we have access to the visible bitmask 2018-06-15 13:59:59 +01:00
Luke Benstead
713fc0a396 Minor fixes to the triangle dropping logic 2018-06-13 21:21:36 +01:00
Luke Benstead
299df08111 Implement logic for dropping invisible triangles from the strip 2018-06-13 20:38:20 +01:00
Luke Benstead
e8e0881db8 Refactor vertex submission to separate perspective division from vertex calculation 2018-06-10 14:25:49 +01:00
Luke Benstead
4d3858d0f0 More clipping work 2018-06-06 19:58:59 +01:00
Luke Benstead
b2a26e58b3 Merge remote-tracking branch 'origin/master' into near-z 2018-06-06 08:40:34 +01:00
Luke Benstead
1baeba1c59 Start working on z-clipping 2018-06-06 08:33:41 +01:00
11 changed files with 542 additions and 24 deletions

View File

@ -1,4 +1,6 @@
#include <float.h>
#include <stdio.h>
#include "clip.h"
ClipResult clipLineToNearZ(const float* v1, const float* v2, const float dist, float* vout, float* t) {
@ -32,3 +34,100 @@ ClipResult clipLineToNearZ(const float* v1, const float* v2, const float dist, f
return CLIP_RESULT_ALL_ON_PLANE;
}
}
TriangleClipResult clipTriangleToNearZ(
const float plane_dist,
const pvr_vertex_t** vertices_in,
const float* w_coordinates_in,
pvr_vertex_t** vertices_out,
float* w_coordinates_out,
unsigned char* visible
) {
const pvr_vertex_t* v1 = vertices_in[0];
const pvr_vertex_t* v2 = vertices_in[1];
const pvr_vertex_t* v3 = vertices_in[2];
const float w1 = w_coordinates_in[0];
const float w2 = w_coordinates_in[1];
const float w3 = w_coordinates_in[2];
pvr_vertex_t* v1out = vertices_out[0];
pvr_vertex_t* v2out = vertices_out[1];
pvr_vertex_t* v3out = vertices_out[2];
pvr_vertex_t* v4out = vertices_out[3];
float* w1out = w_coordinates_out[0];
float* w2out = w_coordinates_out[1];
float* w3out = w_coordinates_out[2];
float* w4out = w_coordinates_out[3];
/* Fast out. Let's just see if everything is in front of the clip plane (and as in OpenGL Z comes out of the screen
* we check to see if they are all < -dist
*/
typedef unsigned char uint8;
*visible = ((v1->z <= -plane_dist) ? 1 : 0) | ((v2->z <= -plane_dist) ? 2 : 0) | ((v3->z <= -plane_dist) ? 4 : 0);
switch(*visible) {
case 0b000:
/* If behind is zero, then none of the vertices are visible */
return TRIANGLE_CLIP_RESULT_DROP_TRIANGLE;
case 0b111:
/* If behind is zero, then none of the vertices are visible */
return TRIANGLE_CLIP_RESULT_NO_CHANGE;
case 0b101:
case 0b110:
case 0b011: {
/* Two vertices are visible */
/* Tricky case. If two vertices are visible then manipulating the other one is going to change the shape of the
* triangle. So we have to clip both lines, and output a new vertex.
*/
return TRIANGLE_CLIP_RESULT_ALTERED_AND_CREATED_VERTEX;
} break;
default: {
/* One vertex is visible */
/* This is the "easy" case, we simply find the vertex which is visible, and clip the lines to the other 2 against the plane */
pvr_vertex_t tmp1, tmp2;
float t1, t2;
if(visible == 0b001) {
clipLineToNearZ(&v1->x, &v2->x, plane_dist, &tmp1.x, &t1);
clipLineToNearZ(&v1->x, &v3->x, plane_dist, &tmp2.x, &t2);
*v1out = *v1;
*v2out = tmp1;
*v3out = tmp2;
*w1out = w1;
*w2out = w1 + ((w2 - w1) * t1);
*w3out = w1 + ((w3 - w1) * t2);
} else if(visible == 0b010) {
clipLineToNearZ(&v2->x, &v1->x, plane_dist, &tmp1.x, &t1);
clipLineToNearZ(&v2->x, &v3->x, plane_dist, &tmp2.x, &t2);
*v1out = tmp1;
*v2out = *v2;
*v3out = tmp2;
*w1out = w2 + ((w1 - w2) * t1);
*w2out = w2;
*w3out = w2 + ((w3 - w2) * t2);
} else {
clipLineToNearZ(&v3->x, &v1->x, plane_dist, &tmp1.x, &t1);
clipLineToNearZ(&v3->x, &v2->x, plane_dist, &tmp2.x, &t2);
*v1out = tmp1;
*v2out = tmp2;
*v3out = *v3;
*w1out = w3 + ((w3 - w1) * t1);
*w2out = w3 + ((w3 - w2) * t2);
*w3out = w3;
}
return TRIANGLE_CLIP_RESULT_ALTERED_VERTICES;
}
}
}

View File

@ -5,6 +5,24 @@
extern "C" {
#endif
/* If we're not on the Dreamcast then define pvr_vertex_t
* (this if for testing only)
*/
#ifndef _arch_dreamcast
typedef struct {
uint32 flags; /**< \brief TA command (vertex flags) */
float x; /**< \brief X coordinate */
float y; /**< \brief Y coordinate */
float z; /**< \brief Z coordinate */
float u; /**< \brief Texture U coordinate */
float v; /**< \brief Texture V coordinate */
uint32 argb; /**< \brief Vertex color */
uint32 oargb; /**< \brief Vertex offset color */
} pvr_vertex_t;
#else
#include <dc/pvr.h>
#endif
typedef enum {
CLIP_RESULT_ALL_IN_FRONT,
CLIP_RESULT_ALL_BEHIND,
@ -15,6 +33,35 @@ typedef enum {
ClipResult clipLineToNearZ(const float* v1, const float* v2, const float dist, float* vout, float* t);
/* There are 4 possible situations we'll hit when clipping triangles:
*
* 1. The entire triangle was in front of the near plane, so we do nothing
* 2. The entire triangle was behind the near plane, so we drop it completely
* 3. One vertex was behind the clip plane. In this case we need to create a new vertex and an additional triangle
* 4. Two vertices were behind the clip plane, we can simply move them so the triangle no longer intersects
*/
typedef enum {
TRIANGLE_CLIP_RESULT_NO_CHANGE,
TRIANGLE_CLIP_RESULT_DROP_TRIANGLE,
TRIANGLE_CLIP_RESULT_ALTERED_AND_CREATED_VERTEX,
TRIANGLE_CLIP_RESULT_ALTERED_VERTICES
} TriangleClipResult;
/* Clips a triangle from a triangle strip to a near-z plane. Alternating triangles in a strip switch vertex ordering
* so the number of the triangle must be passed in (vn - 2).
*
* Note that clipping a triangle with a plane may create a quadrilateral, so this function must have
* a space to output the 4th vertex.
*
* The outputs can be the same as the inputs.
*/
TriangleClipResult clipTriangleToNearZ(
const float plane_dist, const pvr_vertex_t** vertices_in, const float* w_coordinates_in,
pvr_vertex_t* vertices_out, float* w_coordinates_out,
unsigned char* visible
);
#ifdef __cplusplus
}
#endif

212
GL/draw.c
View File

@ -1,4 +1,5 @@
#include <stdio.h>
#include <string.h>
#include "../include/gl.h"
#include "../include/glext.h"
@ -70,20 +71,24 @@ static GLuint byte_size(GLenum type) {
}
}
static void transformVertex(GLfloat* src, float* x, float* y, float* z) {
register float __x __asm__("fr12");
register float __y __asm__("fr13");
register float __z __asm__("fr14");
static GLfloat transformVertexWithoutPerspectiveDivide(GLfloat* src, float* x, float* y, float* z) {
register float __x __asm__("fr12") = (src[0]);
register float __y __asm__("fr13") = (src[1]);
register float __z __asm__("fr14") = (src[2]);
register float __w __asm__("fr15");
__x = src[0];
__y = src[1];
__z = src[2];
mat_trans_fv12()
__asm__ __volatile__(
"fldi1 fr15\n"
"ftrv xmtrx, fv12\n"
: "=f" (__x), "=f" (__y), "=f" (__z)
: "0" (__x), "1" (__y), "2" (__z)
);
*x = __x;
*y = __y;
*z = __z;
return __w;
}
static void _parseColour(uint32* out, const GLubyte* in, GLint size, GLenum type) {
@ -190,6 +195,8 @@ inline void transformNormalToEyeSpace(GLfloat* normal) {
mat_trans_normal3(normal[0], normal[1], normal[2]);
}
/* If this has a value other than zero, it must be positive! */
#define NEAR_DEPTH 0.0001f
static void submitVertices(GLenum mode, GLsizei first, GLsizei count, GLenum type, const GLvoid* indices) {
static GLfloat normal[3] = {0.0f, 0.0f, -1.0f};
@ -202,13 +209,18 @@ static void submitVertices(GLenum mode, GLsizei first, GLsizei count, GLenum typ
const GLsizei elements = (mode == GL_QUADS) ? 4 : (mode == GL_TRIANGLES) ? 3 : (mode == GL_LINES) ? 2 : count;
// Point dest at the first new vertex to populate. This is the size of the container before extending,
// with the additional space for the header.
GLsizei start_of_output = activePolyList()->vector.size + 1;
AlignedVector* list_vector = &activePolyList()->vector;
// Make room for the element + the header
PVRCommand* dst = (PVRCommand*) aligned_vector_extend(&activePolyList()->vector, count + 1);
PVRCommand* dst = (PVRCommand*) aligned_vector_extend(list_vector, count + 1);
// Store a pointer to the header
pvr_poly_hdr_t* hdr = (pvr_poly_hdr_t*) dst;
// Point dest at the first new vertex to populate
dst++;
// Compile
@ -236,7 +248,26 @@ static void submitVertices(GLenum mode, GLsizei first, GLsizei count, GLenum typ
GLboolean lighting_enabled = isLightingEnabled();
GLushort i, last_vertex;
for(i = first; i < count; ++i) {
GLshort rel; // Has to be signed as we drop below zero so we can re-enter the loop at 1.
static AlignedVector w_coordinates;
static GLboolean w_coordinates_initialized = GL_FALSE;
if(!w_coordinates_initialized) {
aligned_vector_init(&w_coordinates, sizeof(GLfloat));
w_coordinates_initialized = GL_TRUE;
}
aligned_vector_resize(&w_coordinates, 0);
static struct {
pvr_vertex_t* vin[3];
GLfloat w[3];
GLubyte vcount;
} Triangle;
Triangle.vcount = 0;
/* Loop 1. Calculate vertex colours, transform, but don't apply perspective division */
for(rel = 0, i = first; i < first + count; ++i, ++rel) {
pvr_vertex_t* vertex = (pvr_vertex_t*) dst;
vertex->u = vertex->v = 0.0f;
vertex->argb = 0;
@ -308,25 +339,158 @@ static void submitVertices(GLenum mode, GLsizei first, GLsizei count, GLenum typ
}
_applyRenderMatrix(); /* Apply the Render Matrix Stack */
transformVertex(&vertex->x, &vertex->x, &vertex->y, &vertex->z);
/* The PVR doesn't support quads, only triangle strips, so we need to
* swap the last two vertices of each set */
if(last_vertex && mode == GL_QUADS) {
/* This vertex becomes the previous vertex so store it*/
pvr_vertex_t tmp = *vertex;
tmp.flags = PVR_CMD_VERTEX;
/* Perform transformation without perspective division. Perspective divide will occur
* per-triangle after clipping */
GLfloat W = transformVertexWithoutPerspectiveDivide(&vertex->x, &vertex->x, &vertex->y, &vertex->z);
/* Overwrite this vertex with the previous one, make it last */
*vertex = *(vertex - 1);
vertex->flags = PVR_CMD_VERTEX_EOL;
Triangle.w[Triangle.vcount] = W;
Triangle.vin[Triangle.vcount] = vertex;
Triangle.vcount++;
if(Triangle.vcount == 3) {
pvr_vertex_t clipped[4];
float clipped_w[4];
GLubyte visible; /* Bitmask of which of the 3 input vertices are visible */
/* Now make the previous one the original last one */
*(vertex - 1) = tmp;
/* OK we have a whole triangle, we may have to clip */
TriangleClipResult tri_result = clipTriangleToNearZ(
NEAR_DEPTH,
Triangle.vin,
Triangle.w,
clipped,
clipped_w,
&visible
);
/* The potential 4 new vertices that can be output by clipping the triangle. Initialized in the below branches */
pvr_vertex_t* vout[4];
if(tri_result == TRIANGLE_CLIP_RESULT_NO_CHANGE) {
/* Nothing changed, we're fine */
} else if(tri_result == TRIANGLE_CLIP_RESULT_DROP_TRIANGLE) {
/* As we're dealing with triangle strips, we have the following situations:
* 1. This is the first trangle. We can drop the first vertex, reverse the other two, subsequent
* triangles will be formed from them. If there are no remaining vertices (i == count - 1) then
* we can drop all three.
* 2. This is the second+ triangle. We mark the second triangle vertex as the "last" vertex, then
* push the second and third vertices again (reversed) to start the new triangle. If there are no
* more vertices (i == count - 1) we can just drop the final vertex.
* By first triangle, it means that rel == 2 or dst - 3 is marked as a "last" vertex.
*/
/* Is this the first triangle in the strip? */
GLboolean first_triangle = (rel == 2) || ((vertex - 3)->flags == PVR_CMD_VERTEX_EOL);
if(first_triangle) {
vout[0] = vertex - 2;
vout[1] = vertex - 1;
vout[2] = vertex;
if(rel == (count - 1)) {
/* Lose all 3 vertices */
aligned_vector_resize(list_vector, list_vector->size - 3);
dst -= 3;
vertex = (pvr_vertex_t*) dst;
/* Next triangle is a new one */
Triangle.vcount = 0;
} else {
vout[0] = vout[2];
/* vout[1] = vout[1]; no-op, just here as a comment so things make a bit more sense */
/* Rewind dst by one as we just lost a vertex */
aligned_vector_resize(list_vector, list_vector->size - 1);
dst--;
vertex = (pvr_vertex_t*) dst;
/* Two vertices are populated for the current triangle now */
Triangle.vcount = 2;
}
} else {
if(rel == (count - 1)) {
/* This is the last vertex in the strip and we're dropping this triangle so just drop a vertex*/
aligned_vector_resize(list_vector, list_vector->size - 1);
dst--;
vertex = (pvr_vertex_t*) dst;
} else {
/* This is a bit weird. We're dropping a triangle, but we have to add an additional vertex. This is because
* if this triangle is in the middle of the strip, and we drop the 3rd vertex then we break the following triangle.
* so what we do is end the triangle strip at vertex 2 of the current triangle, then re-add vertex 2 and vertex 3
* in reverse so that the next triangle works. This might seem wasteful but actually that triangle could be subsequently
* dropped entirely as it'll be the "first_triangle" next time around. */
/* Make room at the end of the vector */
aligned_vector_extend(list_vector, 1);
/* Deal with any realloc that just happened */
dst = aligned_vector_at(list_vector, rel);
vertex = (pvr_vertex_t*) dst;
/* Set up the output pointers */
vout[0] = vertex - 2;
vout[1] = vertex - 1;
vout[2] = vertex;
vout[3] = vertex + 3;
/* Mark second vertex as the end of the strip, duplicate the second vertex
* to create the start of the next strip
*/
*vout[3] = *Triangle.vin[1];
vout[1]->flags = PVR_CMD_VERTEX_EOL;
vout[2]->flags = PVR_CMD_VERTEX;
vout[3]->flags = PVR_CMD_VERTEX;
dst = (PVRCommand*) vout[3];
vertex = vout[3];
/* Current triangle has two vertices */
Triangle.vcount = 2;
}
}
} else if(tri_result == TRIANGLE_CLIP_RESULT_ALTERED_VERTICES) {
/* We're here because a single vertex was visible, the other two vertices were changed */
} else if(tri_result == TRIANGLE_CLIP_RESULT_ALTERED_AND_CREATED_VERTEX) {
}
/* Reset for the next triangle */
Triangle.vin[0] = Triangle.vin[1];
Triangle.vin[1] = Triangle.vin[2];
Triangle.w[0] = Triangle.w[1];
Triangle.w[1] = Triangle.w[2];
Triangle.vcount = 2;
}
++dst;
}
pvr_vertex_t* v = (pvr_vertex_t*) aligned_vector_at(list_vector, start_of_output);
/* Loop 2: Perspective division */
for(rel = 0, i = start_of_output; i < activePolyList()->vector.size; ++rel, ++i) {
GLfloat* w = aligned_vector_at(&w_coordinates, rel);
register float __x __asm__("fr12") = (v->x);
register float __y __asm__("fr13") = (v->y);
register float __z __asm__("fr14") = (v->z);
register float __w __asm__("fr15") = (*w);
__asm__ __volatile__(
"fldi1 fr14\n" \
"fdiv fr15, fr14\n" \
"fmul fr14, fr12\n" \
"fmul fr14, fr13\n" \
: "=f" (__x), "=f" (__y), "=f" (__z)
: "0" (__x), "1" (__y), "2" (__z)
);
v->x = __x;
v->y = __y;
v->z = __z;
++v;
}
}
void APIENTRY glDrawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid* indices) {

View File

@ -4,6 +4,7 @@
#include "../include/gl.h"
#include "../containers/aligned_vector.h"
#include "../containers/named_array.h"
#include "./clip.h"
#define TRACE_ENABLED 0

View File

@ -14,3 +14,5 @@ all:
$(KOS_MAKE) -C ortho2d all
$(KOS_MAKE) -C lerabot01 all
$(KOS_MAKE) -C zclip all
$(KOS_MAKE) -C zclip1 all
$(KOS_MAKE) -C zclip2 all

29
samples/zclip1/Makefile Normal file
View File

@ -0,0 +1,29 @@
TARGET = zclip1.elf
OBJS = main.o
all: rm-elf $(TARGET)
include $(KOS_BASE)/Makefile.rules
clean:
-rm -f $(TARGET) $(OBJS) romdisk.*
rm-elf:
-rm -f $(TARGET) romdisk.*
$(TARGET): $(OBJS) romdisk.o
$(KOS_CC) $(KOS_CFLAGS) $(KOS_LDFLAGS) -o $(TARGET) $(KOS_START) \
$(OBJS) romdisk.o $(OBJEXTRA) -lm -lkosutils $(KOS_LIBS)
romdisk.img:
$(KOS_GENROMFS) -f romdisk.img -d romdisk -v
romdisk.o: romdisk.img
$(KOS_BASE)/utils/bin2o/bin2o romdisk.img romdisk romdisk.o
run: $(TARGET)
$(KOS_LOADER) $(TARGET)
dist:
rm -f $(OBJS) romdisk.o romdisk.img
$(KOS_STRIP) $(TARGET)

68
samples/zclip1/main.c Normal file
View File

@ -0,0 +1,68 @@
#include "gl.h"
#include "glu.h"
#include "glkos.h"
/* A general OpenGL initialization function. Sets all of the initial parameters. */
void InitGL(int Width, int Height) // We call this right after our OpenGL window is created.
{
glClearColor(0.0f, 0.0f, 0.0f, 0.0f); // This Will Clear The Background Color To Black
glDepthFunc(GL_LESS); // The Type Of Depth Test To Do
glEnable(GL_DEPTH_TEST); // Enables Depth Testing
glShadeModel(GL_SMOOTH); // Enables Smooth Color Shading
glMatrixMode(GL_PROJECTION);
glLoadIdentity(); // Reset The Projection Matrix
gluPerspective(45.0f,(GLfloat)Width/(GLfloat)Height,0.1f,100.0f); // Calculate The Aspect Ratio Of The Window
glMatrixMode(GL_MODELVIEW);
}
/* The function called when our window is resized (which shouldn't happen, because we're fullscreen) */
void ReSizeGLScene(int Width, int Height)
{
if (Height == 0) // Prevent A Divide By Zero If The Window Is Too Small
Height = 1;
glViewport(0, 0, Width, Height); // Reset The Current Viewport And Perspective Transformation
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(45.0f,(GLfloat)Width/(GLfloat)Height,0.1f,100.0f);
glMatrixMode(GL_MODELVIEW);
}
/* The main drawing function. */
void DrawGLScene()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear The Screen And The Depth Buffer
glLoadIdentity(); // Reset The View
glDisable(GL_CULL_FACE);
/* Draw a triangle intersecting the screen with a single vertex visible */
glBegin(GL_TRIANGLES);
glVertex3f(0.0f, 0.0f, -5.0f);
glVertex3f(-0.5f, -1.0f, 5.0f);
glVertex3f(0.5, -1.0f, 5.0f);
glEnd();
// swap buffers to display, since we're double buffered.
glKosSwapBuffers();
}
int main(int argc, char **argv)
{
glKosInit();
InitGL(640, 480);
ReSizeGLScene(640, 480);
while(1) {
DrawGLScene();
}
return 0;
}

View File

29
samples/zclip2/Makefile Normal file
View File

@ -0,0 +1,29 @@
TARGET = zclip2.elf
OBJS = main.o
all: rm-elf $(TARGET)
include $(KOS_BASE)/Makefile.rules
clean:
-rm -f $(TARGET) $(OBJS) romdisk.*
rm-elf:
-rm -f $(TARGET) romdisk.*
$(TARGET): $(OBJS) romdisk.o
$(KOS_CC) $(KOS_CFLAGS) $(KOS_LDFLAGS) -o $(TARGET) $(KOS_START) \
$(OBJS) romdisk.o $(OBJEXTRA) -lm -lkosutils $(KOS_LIBS)
romdisk.img:
$(KOS_GENROMFS) -f romdisk.img -d romdisk -v
romdisk.o: romdisk.img
$(KOS_BASE)/utils/bin2o/bin2o romdisk.img romdisk romdisk.o
run: $(TARGET)
$(KOS_LOADER) $(TARGET)
dist:
rm -f $(OBJS) romdisk.o romdisk.img
$(KOS_STRIP) $(TARGET)

79
samples/zclip2/main.c Normal file
View File

@ -0,0 +1,79 @@
#include "gl.h"
#include "glu.h"
#include "glkos.h"
/* A general OpenGL initialization function. Sets all of the initial parameters. */
void InitGL(int Width, int Height) // We call this right after our OpenGL window is created.
{
glClearColor(0.0f, 0.0f, 0.0f, 0.0f); // This Will Clear The Background Color To Black
glClearDepth(1.0); // Enables Clearing Of The Depth Buffer
glDepthFunc(GL_LESS); // The Type Of Depth Test To Do
glEnable(GL_DEPTH_TEST); // Enables Depth Testing
glShadeModel(GL_SMOOTH); // Enables Smooth Color Shading
glMatrixMode(GL_PROJECTION);
glLoadIdentity(); // Reset The Projection Matrix
gluPerspective(45.0f,(GLfloat)Width/(GLfloat)Height,0.1f,100.0f); // Calculate The Aspect Ratio Of The Window
glMatrixMode(GL_MODELVIEW);
}
/* The function called when our window is resized (which shouldn't happen, because we're fullscreen) */
void ReSizeGLScene(int Width, int Height)
{
if (Height == 0) // Prevent A Divide By Zero If The Window Is Too Small
Height = 1;
glViewport(0, 0, Width, Height); // Reset The Current Viewport And Perspective Transformation
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(45.0f,(GLfloat)Width/(GLfloat)Height,0.1f,100.0f);
glMatrixMode(GL_MODELVIEW);
}
/* The main drawing function. */
void DrawGLScene()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear The Screen And The Depth Buffer
glLoadIdentity(); // Reset The View
glTranslatef(-1.5f,0.0f,-6.0f); // Move Left 1.5 Units And Into The Screen 6.0
// draw a triangle
glBegin(GL_POLYGON); // start drawing a polygon
glVertex3f( 0.0f, 1.0f, 0.0f); // Top
glVertex3f( 1.0f,-1.0f, 0.0f); // Bottom Right
glVertex3f(-1.0f,-1.0f, 0.0f); // Bottom Left
glEnd(); // we're done with the polygon
glTranslatef(3.0f,0.0f,0.0f); // Move Right 3 Units
// draw a square (quadrilateral)
glBegin(GL_QUADS); // start drawing a polygon (4 sided)
glVertex3f(-1.0f, 1.0f, 0.0f); // Top Left
glVertex3f( 1.0f, 1.0f, 0.0f); // Top Right
glVertex3f( 1.0f,-1.0f, 0.0f); // Bottom Right
glVertex3f(-1.0f,-1.0f, 0.0f); // Bottom Left
glEnd(); // done with the polygon
// swap buffers to display, since we're double buffered.
glKosSwapBuffers();
}
int main(int argc, char **argv)
{
glKosInit();
InitGL(640, 480);
ReSizeGLScene(640, 480);
while(1) {
DrawGLScene();
}
return 0;
}

View File