Merge branch 'prim_modes' into 'master'

Add remainder of OpenGL primitive modes

See merge request simulant/GLdc!127
This commit is contained in:
Luke Benstead 2024-10-02 12:51:47 +00:00
commit 57d5a59d65
6 changed files with 383 additions and 27 deletions

View File

@ -209,6 +209,7 @@ gen_sample(scissor samples/scissor/main.c)
gen_sample(polymark samples/polymark/main.c)
gen_sample(cubes samples/cubes/main.cpp)
gen_sample(zclip_test tests/zclip/main.cpp)
gen_sample(primitive_modes samples/primitive_modes/main.c)
if(PLATFORM_DREAMCAST)
gen_sample(trimark samples/trimark/main.c)

196
GL/draw.c
View File

@ -435,21 +435,147 @@ GL_FORCE_INLINE void genTriangleStrip(Vertex* output, GLuint count) {
output[count - 1].flags = GPU_CMD_VERTEX_EOL;
}
static void genTriangleFan(Vertex* output, GLuint count) {
gl_assert(count <= 255);
#define QUADSTRIP_COUNT(count) (((count) - 2) * 2)
static GL_NO_INLINE void genQuadStrip(Vertex* output, GLuint count) {
Vertex* dst = output + QUADSTRIP_COUNT(count) - 1;
Vertex* src = output + count;//(count - 1);
Vertex* dst = output + (((count - 2) * 3) - 1);
Vertex* src = output + (count - 1);
for (; count > 2; count -= 2) {
// Have to copy because of src/dst overlapping on first quad
Vertex src1 = src[-1], src2 = src[-2], src3 = src[-3], src4 = src[-4];
GLubyte i = count - 2;
while(i--) {
*dst = *src--;
*dst = src3;
(*dst--).flags = GPU_CMD_VERTEX_EOL;
*dst-- = src4;
*dst-- = src1;
*dst-- = src2;
src -= 2;
}
}
#define TRIFAN_COUNT(count) (((count) - 2) * 3)
static GL_NO_INLINE void genTriangleFan(Vertex* output, GLuint count) {
Vertex* dst = output + TRIFAN_COUNT(count) - 1;
Vertex* src = output + count - 1;
// Triangles generated as {first vertex, prior vertex, current vertex}
// e.g. {v1, v2, v3, v4} produces {v1, v2, v3}, {v1, v3, v4}
for (; count > 2; count--) {
*dst = *src--;
(*dst--).flags = GPU_CMD_VERTEX_EOL;
*dst-- = *src;
*dst-- = *output;
}
}
#define POINTS_COUNT(count) ((count) * 4)
static GL_NO_INLINE void genPoints(Vertex* output, GLuint count) {
Vertex* dst = output + POINTS_COUNT(count) - 1;
Vertex* src = output + count - 1;
float half_size = HALF_POINT_SIZE;
// Expands v to { v + (-S/2,S/2), v + (S/2,S/2), v + (-S/2,S/2), (S/2,-S/2) }
for (; count > 0; count--, src--) {
*dst = *src;
dst->flags = GPU_CMD_VERTEX_EOL;
dst->xyz[0] -= half_size; dst->xyz[1] -= half_size;
dst--;
*dst = *src;
dst->xyz[0] += half_size; dst->xyz[1] -= half_size;
dst--;
*dst = *src;
dst->xyz[0] -= half_size; dst->xyz[1] += half_size;
dst--;
*dst = *src;
dst->xyz[0] += half_size; dst->xyz[1] += half_size;
dst--;
}
}
// Heavily based on the pvrline example by jnmartin84
// Which is based on https://devcry.heiho.net/html/2017/20170820-opengl-line-drawing.html
static Vertex* draw_line(Vertex* dst, Vertex* v1, Vertex* v2) {
Vertex ov1 = *v1;
Vertex ov2 = *v2;
// TODO don't copy unless dst might overlap v1/v2
// Essentially "expands" a line into a quad by
// 1) Calculating normal of the line from v1 to v2
// 2) Scaling normal by the line width
// 3) Offseting the endpoints wrt the scaled normal
float dx = ov2.xyz[0] - ov1.xyz[0];
float dy = ov2.xyz[1] - ov1.xyz[1];
float inverse_mag = fast_rsqrt((dx*dx) + (dy*dy)) * HALF_LINE_WIDTH;
float nx = -dy * inverse_mag;
float ny = dx * inverse_mag;
// Expand first endpoint both "up" and "down"
*dst = ov1;
dst->flags = GPU_CMD_VERTEX_EOL;
dst->xyz[0] += nx;
dst->xyz[1] += ny;
dst--;
*dst = ov1;
dst->xyz[0] -= nx;
dst->xyz[1] -= ny;
dst--;
// Expand second endpoint both "up" and "down"
*dst = ov2;
dst->xyz[0] += nx;
dst->xyz[1] += ny;
dst--;
*dst = ov2;
dst->xyz[0] -= nx;
dst->xyz[1] -= ny;
dst--;
return dst;
}
#define LINES_COUNT(count) (((count) / 2) * 4)
static GL_NO_INLINE void genLines(Vertex* output, GLuint count) {
Vertex* dst = output + LINES_COUNT(count) - 1;
Vertex* src = output + count - 1;
// Draws line using two vertices
for (; count >= 2; count -= 2, src -= 2) {
dst = draw_line(dst, src, src - 1);
}
}
#define LINE_STRIP_COUNT(count) (((count) - 1) * 4)
static GL_NO_INLINE void genLineStrip(Vertex* output, GLuint count) {
Vertex* dst = output + LINE_STRIP_COUNT(count) - 1;
Vertex* src = output + count - 1;
// Draws line using current and prior vertex
for (; count > 1; count--, src--) {
dst = draw_line(dst, src, src - 1);
}
}
#define LINE_LOOP_COUNT(count) ((count) * 4)
static GL_NO_INLINE void genLineLoop(Vertex* output, GLuint count) {
Vertex* dst = output + LINE_LOOP_COUNT(count) - 1;
Vertex* src = output + count - 1;
Vertex last = *src, first = *output;
// Draws line using current and prior vertex
for (; count > 1; count--, src--) {
dst = draw_line(dst, src, src - 1);
}
// Connect first and last vertex
draw_line(dst, &first, &last);
}
typedef void (*ReadPositionFunc)(const GLubyte*, GLubyte*);
typedef void (*ReadDiffuseFunc)(const GLubyte*, GLubyte*);
typedef void (*ReadUVFunc)(const GLubyte*, GLubyte*);
@ -891,11 +1017,28 @@ static void generate(SubmissionTarget* target, const GLenum mode, const GLsizei
case GL_QUADS:
genQuads(it, count);
break;
case GL_TRIANGLE_STRIP:
genTriangleStrip(it, count);
break;
case GL_QUAD_STRIP:
genQuadStrip(it, count);
break;
case GL_TRIANGLE_FAN:
genTriangleFan(it, count);
break;
case GL_TRIANGLE_STRIP:
genTriangleStrip(it, count);
case GL_POINTS:
genPoints(it, count);
break;
case GL_LINES:
genLines(it, count);
break;
case GL_LINE_STRIP:
genLineStrip(it, count);
break;
case GL_LINE_LOOP:
genLineLoop(it, count);
break;
default:
gl_assert(0 && "Not Implemented");
@ -1093,6 +1236,23 @@ void _glInitSubmissionTarget() {
target->extras = &VERTEX_EXTRAS;
}
GL_FORCE_INLINE GLuint calcFinalVertices(GLenum mode, GLuint count) {
switch (mode) {
case GL_POINTS:
return POINTS_COUNT(count);
case GL_LINE_LOOP:
return LINE_LOOP_COUNT(count);
case GL_LINE_STRIP:
return LINE_STRIP_COUNT(count);
case GL_LINES:
return LINES_COUNT(count);
case GL_TRIANGLE_FAN:
return TRIFAN_COUNT(count);
case GL_QUAD_STRIP:
return QUADSTRIP_COUNT(count);
}
return count;
}
GL_FORCE_INLINE void submitVertices(GLenum mode, GLsizei first, GLuint count, GLenum type, const GLvoid* indices) {
@ -1102,14 +1262,10 @@ GL_FORCE_INLINE void submitVertices(GLenum mode, GLsizei first, GLuint count, GL
TRACE();
/* Do nothing if vertices aren't enabled */
if(!(ENABLED_VERTEX_ATTRIBUTES & VERTEX_ENABLED_FLAG)) {
return;
}
if(!(ENABLED_VERTEX_ATTRIBUTES & VERTEX_ENABLED_FLAG)) return;
/* No vertices? Do nothing */
if(!count) {
return;
}
if(!count) return;
/* Polygons are treated as triangle fans, the only time this would be a
* problem is if we supported glPolygonMode(..., GL_LINE) but we don't.
@ -1131,14 +1287,6 @@ GL_FORCE_INLINE void submitVertices(GLenum mode, GLsizei first, GLuint count, GL
}
}
if(mode == GL_LINE_STRIP || mode == GL_LINES) {
fprintf(stderr, "Line drawing is currently unsupported\n");
return;
}
// We don't handle this any further, so just make sure we never pass it down */
gl_assert(mode != GL_POLYGON);
target->output = _glActivePolyList();
gl_assert(target->output);
gl_assert(extras);
@ -1147,7 +1295,7 @@ GL_FORCE_INLINE void submitVertices(GLenum mode, GLsizei first, GLuint count, GL
GLboolean header_required = (vector_size == 0) || _glGPUStateIsDirty();
target->count = (mode == GL_TRIANGLE_FAN) ? ((count - 2) * 3) : count;
target->count = calcFinalVertices(mode, count);
target->header_offset = vector_size;
target->start_offset = target->header_offset + (header_required ? 1 : 0);

View File

@ -25,6 +25,7 @@ extern void* memcpy4 (void *dest, const void *src, size_t count);
#define GL_NO_INSTRUMENT inline __attribute__((no_instrument_function))
#define GL_INLINE_DEBUG GL_NO_INSTRUMENT __attribute__((always_inline))
#define GL_FORCE_INLINE static GL_INLINE_DEBUG
#define GL_NO_INLINE __attribute__((noinline))
#define _GL_UNUSED(x) (void)(x)
#define _PACK4(v) ((v * 0xF) / 0xFF)
@ -259,6 +260,12 @@ do { \
memcpy_vertex(b, &c); \
} while(0)
#ifdef __DREAMCAST__
#define fast_rsqrt(x) frsqrt(x)
#else
#define fast_rsqrt(x) (1.0f / __builtin_sqrtf(x))
#endif
/* ClipVertex doesn't have room for these, so we need to parse them
* out separately. Potentially 'w' will be housed here if we support oargb */
typedef struct {
@ -320,6 +327,9 @@ void _glMatrixLoadModelViewProjection();
extern GLfloat DEPTH_RANGE_MULTIPLIER_L;
extern GLfloat DEPTH_RANGE_MULTIPLIER_H;
extern GLfloat HALF_LINE_WIDTH;
extern GLfloat HALF_POINT_SIZE;
Matrix4x4* _glGetProjectionMatrix();
Matrix4x4* _glGetModelViewMatrix();

View File

@ -3,7 +3,8 @@
#include <stdio.h>
#include "private.h"
GLfloat HALF_LINE_WIDTH = 1.0f / 2.0f;
GLfloat HALF_POINT_SIZE = 1.0f / 2.0f;
static struct {
GLboolean is_dirty;
@ -773,7 +774,11 @@ GLAPI void APIENTRY glAlphaFunc(GLenum func, GLclampf ref) {
}
void glLineWidth(GLfloat width) {
_GL_UNUSED(width);
HALF_LINE_WIDTH = width / 2.0f;
}
void glPointSize(GLfloat size) {
HALF_POINT_SIZE = size / 2.0f;
}
void glPolygonOffset(GLfloat factor, GLfloat units) {

View File

@ -552,6 +552,10 @@ GLAPI GLvoid APIENTRY glRecti(GLint x1, GLint y1, GLint x2, GLint y2);
GLAPI GLvoid APIENTRY glRectiv(const GLint *v1, const GLint *v2);
#define glRectsv glRectiv
/* Primitive configuration */
GLAPI void APIENTRY glLineWidth(GLfloat width);
GLAPI void APIENTRY glPointSize(GLfloat size);
/* Enable / Disable Capability */
/* Currently Supported Capabilities:
GL_TEXTURE_2D
@ -742,7 +746,6 @@ GLAPI GLenum APIENTRY glGetError(void);
/* Non Operational Stubs for portability */
GLAPI void APIENTRY glAlphaFunc(GLenum func, GLclampf ref);
GLAPI void APIENTRY glLineWidth(GLfloat width);
GLAPI void APIENTRY glPolygonMode(GLenum face, GLenum mode);
GLAPI void APIENTRY glPolygonOffset(GLfloat factor, GLfloat units);
GLAPI void APIENTRY glGetTexParameterfv(GLenum target, GLenum pname, GLfloat *params);

View File

@ -0,0 +1,189 @@
#include <GL/gl.h>
#include <math.h>
#include <stdlib.h>
#ifdef SDL2_BUILD
#include <SDL2/SDL.h>
static SDL_Window* win_handle;
#else
#include <GL/glkos.h>
#endif
static void DrawLineLoop(float y) {
glBegin(GL_LINE_LOOP);
glColor3f(1.0f, 0.0f, 0.0f); glVertex2f(410.0f, y + 10.0f);
glColor3f(0.0f, 1.0f, 0.0f); glVertex2f(490.0f, y + 10.0f);
glColor3f(0.0f, 0.0f, 1.0f); glVertex2f(490.0f, y + 90.0f);
glColor3f(1.0f, 1.0f, 1.0f); glVertex2f(410.0f, y + 90.0f);
glEnd();
}
static void DrawLineStrip(float y) {
glBegin(GL_LINE_STRIP);
glColor3f(1.0f, 0.0f, 0.0f); glVertex2f(310.0f, y + 10.0f);
glColor3f(0.0f, 1.0f, 0.0f); glVertex2f(390.0f, y + 10.0f);
glColor3f(0.0f, 0.0f, 1.0f); glVertex2f(390.0f, y + 90.0f);
glColor3f(1.0f, 1.0f, 1.0f); glVertex2f(310.0f, y + 90.0f);
glEnd();
}
static void DrawLine(float y) {
glBegin(GL_LINES);
glColor3f(1.0f, 0.0f, 0.0f); glVertex2f(210.0f, y + 10.0f);
glColor3f(0.0f, 1.0f, 0.0f); glVertex2f(290.0f, y + 10.0f);
glColor3f(0.0f, 0.0f, 1.0f); glVertex2f(290.0f, y + 90.0f);
glColor3f(1.0f, 1.0f, 1.0f); glVertex2f(210.0f, y + 90.0f);
glColor3f(1.0f, 0.0f, 0.0f); glVertex2f(230.0f, y + 25.0f);
glColor3f(0.0f, 1.0f, 0.0f); glVertex2f(250.0f, y + 75.0f);
glColor3f(0.0f, 0.0f, 1.0f); glVertex2f(260.0f, y + 75.0f);
glColor3f(1.0f, 1.0f, 1.0f); glVertex2f(280.0f, y + 45.0f);
glEnd();
}
static void DrawPoint(float y) {
glBegin(GL_POINTS);
glColor3f(1.0f, 0.0f, 0.0f); glVertex2f(110.0f, y + 10.0f);
glColor3f(0.0f, 1.0f, 0.0f); glVertex2f(190.0f, y + 10.0f);
glColor3f(0.0f, 0.0f, 1.0f); glVertex2f(190.0f, y + 90.0f);
glColor3f(1.0f, 1.0f, 1.0f); glVertex2f(110.0f, y + 90.0f);
glEnd();
}
static void DrawQuad(float y) {
glBegin(GL_QUADS);
glColor3f(1.0f, 0.0f, 0.0f); glVertex2f(10.0f, y + 10.0f);
glColor3f(0.0f, 1.0f, 0.0f); glVertex2f(90.0f, y + 10.0f);
glColor3f(0.0f, 0.0f, 1.0f); glVertex2f(90.0f, y + 90.0f);
glColor3f(1.0f, 1.0f, 1.0f); glVertex2f(10.0f, y + 90.0f);
glColor3f(1.0f, 0.0f, 0.0f); glVertex2f(110.0f, y + 10.0f);
glColor3f(0.0f, 1.0f, 0.0f); glVertex2f(190.0f, y + 10.0f);
glColor3f(0.0f, 0.0f, 1.0f); glVertex2f(190.0f, y + 90.0f);
glColor3f(1.0f, 1.0f, 1.0f); glVertex2f(110.0f, y + 90.0f);
glEnd();
}
static void DrawQuadStrip(float y) {
glBegin(GL_QUAD_STRIP);
glColor3f(1.0f, 0.0f, 0.0f); glVertex2f(210.0f, y + 10.0f);
glColor3f(0.0f, 1.0f, 0.0f); glVertex2f(290.0f, y + 10.0f);
glColor3f(0.0f, 0.0f, 1.0f); glVertex2f(290.0f, y + 90.0f);
glColor3f(1.0f, 1.0f, 1.0f); glVertex2f(210.0f, y + 90.0f);
glColor3f(1.0f, 0.0f, 0.0f); glVertex2f(310.0f, y + 10.0f);
glColor3f(0.0f, 1.0f, 0.0f); glVertex2f(390.0f, y + 10.0f);
glColor3f(0.0f, 0.0f, 1.0f); glVertex2f(390.0f, y + 90.0f);
glColor3f(1.0f, 1.0f, 1.0f); glVertex2f(310.0f, y + 90.0f);
glEnd();
}
static void DrawTriList(float y) {
glBegin(GL_TRIANGLES);
glColor3f(1.0f, 0.0f, 0.0f); glVertex2f( 10.0f, y + 10.0f);
glColor3f(0.0f, 1.0f, 0.0f); glVertex2f( 90.0f, y + 10.0f);
glColor3f(0.0f, 0.0f, 1.0f); glVertex2f( 90.0f, y + 90.0f);
glColor3f(1.0f, 0.0f, 0.0f); glVertex2f(110.0f, y + 10.0f);
glColor3f(0.0f, 1.0f, 0.0f); glVertex2f(190.0f, y + 10.0f);
glColor3f(0.0f, 0.0f, 1.0f); glVertex2f(190.0f, y + 90.0f);
glEnd();
}
static void DrawTriStrip(float y) {
glBegin(GL_TRIANGLE_STRIP);
glColor3f(1.0f, 0.0f, 0.0f); glVertex2f(210.0f, y + 10.0f);
glColor3f(0.0f, 1.0f, 0.0f); glVertex2f(290.0f, y + 10.0f);
glColor3f(0.0f, 0.0f, 1.0f); glVertex2f(290.0f, y + 90.0f);
glColor3f(1.0f, 1.0f, 1.0f); glVertex2f(210.0f, y + 90.0f);
glColor3f(1.0f, 0.0f, 0.0f); glVertex2f(310.0f, y + 10.0f);
glColor3f(0.0f, 1.0f, 0.0f); glVertex2f(390.0f, y + 10.0f);
glColor3f(0.0f, 0.0f, 1.0f); glVertex2f(390.0f, y + 90.0f);
glColor3f(1.0f, 1.0f, 1.0f); glVertex2f(310.0f, y + 90.0f);
glEnd();
}
static void DrawTriFan(float y) {
glBegin(GL_TRIANGLE_FAN);
glColor3f(1.0f, 0.0f, 0.0f); glVertex2f(410.0f, y + 10.0f);
glColor3f(0.0f, 1.0f, 0.0f); glVertex2f(490.0f, y + 10.0f);
glColor3f(0.0f, 0.0f, 1.0f); glVertex2f(445.0f, y + 90.0f);
glColor3f(0.0f, 1.0f, 0.0f); glVertex2f(590.0f, y + 10.0f);
glColor3f(1.0f, 1.0f, 1.0f); glVertex2f(510.0f, y + 45.0f);
glEnd();
}
int main(int argc, char *argv[]) {
#ifdef SDL2_BUILD
SDL_Init(SDL_INIT_EVERYTHING);
win_handle = SDL_CreateWindow("Shapes", 0, 0, 640, 480, SDL_WINDOW_OPENGL);
SDL_GL_CreateContext(win_handle);
#else
glKosInit();
#endif
glClearColor(0.5f, 0.5f, 0.5f, 1);
glViewport(0, 0, 640, 480);
float mat[4][4] = { 0 };
float L = 0, T = 0, R = 640, B = 480, N = -100, F = 100;
mat[0][0] = 2.0f / (R - L);
mat[1][1] = 2.0f / (T - B);
mat[2][2] = -2.0f / (F - N);
mat[3][0] = -(R + L) / (R - L);
mat[3][1] = -(T + B) / (T - B);
mat[3][2] = -(F + N) / (F - N);
mat[3][3] = 1;
glLoadMatrixf(mat);
int running = 1;
while (running) {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
#ifdef SDL2_BUILD
SDL_Event event;
while (SDL_PollEvent(&event)) {
if(event.type == SDL_QUIT) running = 0;
}
#endif
DrawTriStrip(300);
DrawTriFan(300);
DrawTriList(300);
DrawQuadStrip(200);
DrawQuad(200);
glPointSize(5);
DrawPoint(100);
glLineWidth(0.5f);
DrawLineLoop(100);
glLineWidth(2);
DrawLineStrip(100);
glLineWidth(10);
DrawLine(100);
glPointSize(1);
glLineWidth(1);
DrawPoint(0);
DrawLineLoop(0);
DrawLineStrip(0);
DrawLine(0);
glShadeModel(GL_FLAT);
DrawQuad(400);
DrawTriStrip(400);
glShadeModel(GL_SMOOTH);
#ifdef SDL2_BUILD
SDL_GL_SwapWindow(win_handle);
#else
glKosSwapBuffers();
#endif
}
return 0;
}