1 /* ResidualVM - A 3D game interpreter
2  *
3  * ResidualVM is the legal property of its developers, whose names
4  * are too numerous to list here. Please refer to the AUTHORS
5  * file distributed with this source distribution.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20  *
21  */
22 
23 /*
24  * This file is based on, or a modified version of code from TinyGL (C) 1997-1998 Fabrice Bellard,
25  * which is licensed under the zlib-license (see LICENSE).
26  * It also has modifications by the ResidualVM-team, which are covered under the GPLv2 (or later).
27  */
28 
29 #define FORBIDDEN_SYMBOL_EXCEPTION_FILE
30 #define FORBIDDEN_SYMBOL_EXCEPTION_fprintf
31 #define FORBIDDEN_SYMBOL_EXCEPTION_fputc
32 #define FORBIDDEN_SYMBOL_EXCEPTION_stderr
33 
34 #include "graphics/tinygl/zgl.h"
35 
36 namespace TinyGL {
37 
38 static const char *op_table_str[] = {
39 #define ADD_OP(a, b, c) "gl" #a " " #c,
40 
41 #include "graphics/tinygl/opinfo.h"
42 };
43 
44 static void (*op_table_func[])(GLContext *, GLParam *) = {
45 #define ADD_OP(a, b, c) glop ## a ,
46 
47 #include "graphics/tinygl/opinfo.h"
48 };
49 
50 static int op_table_size[] = {
51 #define ADD_OP(a, b, c) b + 1 ,
52 
53 #include "graphics/tinygl/opinfo.h"
54 };
55 
gl_get_context()56 GLContext *gl_get_context() {
57 	return gl_ctx;
58 }
59 
find_list(GLContext * c,unsigned int list)60 static GLList *find_list(GLContext *c, unsigned int list) {
61 	return c->shared_state.lists[list];
62 }
63 
delete_list(GLContext * c,int list)64 static void delete_list(GLContext *c, int list) {
65 	GLParamBuffer *pb, *pb1;
66 	GLList *l;
67 
68 	l = find_list(c, list);
69 	assert(l);
70 
71 	// free param buffer
72 	pb = l->first_op_buffer;
73 	while (pb) {
74 		pb1 = pb->next;
75 		gl_free(pb);
76 		pb = pb1;
77 	}
78 
79 	gl_free(l);
80 	c->shared_state.lists[list] = NULL;
81 }
82 
alloc_list(GLContext * c,int list)83 static GLList *alloc_list(GLContext *c, int list) {
84 	GLList *l;
85 	GLParamBuffer *ob;
86 
87 	l = (GLList *)gl_zalloc(sizeof(GLList));
88 	ob = (GLParamBuffer *)gl_zalloc(sizeof(GLParamBuffer));
89 
90 	ob->next = NULL;
91 	l->first_op_buffer = ob;
92 
93 	ob->ops[0].op = OP_EndList;
94 
95 	c->shared_state.lists[list] = l;
96 	return l;
97 }
98 
gl_print_op(FILE * f,GLParam * p)99 void gl_print_op(FILE *f, GLParam *p) {
100 	int op;
101 	const char *s;
102 
103 	op = p[0].op;
104 	p++;
105 	s = op_table_str[op];
106 	while (*s != 0) {
107 		if (*s == '%') {
108 			s++;
109 			switch (*s++) {
110 			case 'f':
111 				fprintf(f, "%g", p[0].f);
112 				break;
113 			default:
114 				fprintf(f, "%d", p[0].i);
115 				break;
116 			}
117 			p++;
118 		} else {
119 			fputc(*s, f);
120 			s++;
121 		}
122 	}
123 	fprintf(f, "\n");
124 }
125 
126 
gl_compile_op(GLContext * c,GLParam * p)127 void gl_compile_op(GLContext *c, GLParam *p) {
128 	int op, op_size;
129 	GLParamBuffer *ob, *ob1;
130 	int index;
131 
132 	op = p[0].op;
133 	op_size = op_table_size[op];
134 	index = c->current_op_buffer_index;
135 	ob = c->current_op_buffer;
136 
137 	// we should be able to add a NextBuffer opcode
138 	if ((index + op_size) > (OP_BUFFER_MAX_SIZE - 2)) {
139 
140 		ob1 = (GLParamBuffer *)gl_zalloc(sizeof(GLParamBuffer));
141 		ob1->next = NULL;
142 
143 		ob->next = ob1;
144 		ob->ops[index].op = OP_NextBuffer;
145 		ob->ops[index + 1].p = (void *)ob1;
146 
147 		c->current_op_buffer = ob1;
148 		ob = ob1;
149 		index = 0;
150 	}
151 
152 	for (int i = 0; i < op_size; i++) {
153 		ob->ops[index] = p[i];
154 		index++;
155 	}
156 	c->current_op_buffer_index = index;
157 }
158 
gl_add_op(GLParam * p)159 void gl_add_op(GLParam *p) {
160 	GLContext *c = gl_get_context();
161 	int op;
162 
163 	op = p[0].op;
164 	if (c->exec_flag) {
165 		op_table_func[op](c, p);
166 	}
167 	if (c->compile_flag) {
168 		gl_compile_op(c, p);
169 	}
170 	if (c->print_flag) {
171 		gl_print_op(stderr, p);
172 	}
173 }
174 
175 // this opcode is never called directly
glopEndList(GLContext *,GLParam *)176 void glopEndList(GLContext *, GLParam *) {
177 	assert(0);
178 }
179 
180 // this opcode is never called directly
glopNextBuffer(GLContext *,GLParam *)181 void glopNextBuffer(GLContext *, GLParam *) {
182 	assert(0);
183 }
184 
glopCallList(GLContext * c,GLParam * p)185 void glopCallList(GLContext *c, GLParam *p) {
186 	GLList *l;
187 	int list, op;
188 
189 	list = p[1].ui;
190 	l = find_list(c, list);
191 	if (!l)
192 		error("list %d not defined", list);
193 	p = l->first_op_buffer->ops;
194 
195 	while (1) {
196 		op = p[0].op;
197 		if (op == OP_EndList)
198 			break;
199 		if (op == OP_NextBuffer) {
200 			p = (GLParam *)p[1].p;
201 		} else {
202 			op_table_func[op](c, p);
203 			p += op_table_size[op];
204 		}
205 	}
206 }
207 
glNewList(unsigned int list,int mode)208 void glNewList(unsigned int list, int mode) {
209 	GLList *l;
210 	GLContext *c = gl_get_context();
211 
212 	assert(mode == TGL_COMPILE || mode == TGL_COMPILE_AND_EXECUTE);
213 	assert(c->compile_flag == 0);
214 
215 	l = find_list(c, list);
216 	if (l)
217 		delete_list(c, list);
218 	l = alloc_list(c, list);
219 
220 	c->current_op_buffer = l->first_op_buffer;
221 	c->current_op_buffer_index = 0;
222 
223 	c->compile_flag = 1;
224 	c->exec_flag = (mode == TGL_COMPILE_AND_EXECUTE);
225 }
226 
glEndList()227 void glEndList() {
228 	GLContext *c = gl_get_context();
229 	GLParam p[1];
230 
231 	assert(c->compile_flag == 1);
232 
233 	// end of list
234 	p[0].op = OP_EndList;
235 	gl_compile_op(c, p);
236 
237 	c->compile_flag = 0;
238 	c->exec_flag = 1;
239 }
240 
glIsList(unsigned int list)241 int glIsList(unsigned int list) {
242 	GLContext *c = gl_get_context();
243 	GLList *l = find_list(c, list);
244 
245 	return (l != NULL);
246 }
247 
glGenLists(int range)248 unsigned int glGenLists(int range) {
249 	GLContext *c = gl_get_context();
250 	int count, list;
251 	GLList **lists;
252 
253 	lists = c->shared_state.lists;
254 	count = 0;
255 	for (int i = 0; i < MAX_DISPLAY_LISTS; i++) {
256 		if (!lists[i]) {
257 			count++;
258 			if (count == range) {
259 				list = i - range + 1;
260 				for (int j = 0; j < range; j++) {
261 					alloc_list(c, list + j);
262 				}
263 				return list;
264 			}
265 		} else {
266 			count = 0;
267 		}
268 	}
269 	return 0;
270 }
271 
272 } // end of namespace TinyGL
273