rev |
line source |
nuclear@2
|
1 #include <stdio.h>
|
nuclear@2
|
2 #include <stdlib.h>
|
nuclear@2
|
3 #include <string.h>
|
nuclear@2
|
4 #include <assert.h>
|
nuclear@2
|
5 #include <windows.h>
|
nuclear@2
|
6 #include <GL/gl.h>
|
nuclear@2
|
7 #include "glext.h"
|
nuclear@2
|
8 #include "wglext.h"
|
nuclear@2
|
9 #include "app.h"
|
nuclear@2
|
10
|
nuclear@2
|
11 static void draw_screen(long time_msec);
|
nuclear@2
|
12 static unsigned int create_program(const char *vsdr, const char *psdr);
|
nuclear@2
|
13 static unsigned int create_shader(unsigned int type, const char *sdr);
|
nuclear@2
|
14 static unsigned int next_pow2(unsigned int x);
|
nuclear@2
|
15 static int enable_vsync(void);
|
nuclear@2
|
16 static int init_glext(void);
|
nuclear@2
|
17 static void calc_image_proj(float img_aspect, float *xform);
|
nuclear@2
|
18
|
nuclear@2
|
19 extern int scr_width, scr_height;
|
nuclear@2
|
20
|
nuclear@2
|
21 PFNWGLSWAPINTERVALEXTPROC wgl_swap_interval;
|
nuclear@2
|
22
|
nuclear@2
|
23 /* multitexture */
|
nuclear@2
|
24 PFNGLACTIVETEXTUREPROC gl_active_texture;
|
nuclear@2
|
25
|
nuclear@2
|
26 /* shader API entry points */
|
nuclear@2
|
27 PFNGLCREATEPROGRAMPROC gl_create_program;
|
nuclear@2
|
28 PFNGLDELETEPROGRAMPROC gl_delete_program;
|
nuclear@2
|
29 PFNGLCREATESHADERPROC gl_create_shader;
|
nuclear@2
|
30 PFNGLDELETESHADERPROC gl_delete_shader;
|
nuclear@2
|
31 PFNGLSHADERSOURCEPROC gl_shader_source;
|
nuclear@2
|
32 PFNGLCOMPILESHADERPROC gl_compile_shader;
|
nuclear@2
|
33 PFNGLGETSHADERIVPROC gl_get_shaderiv;
|
nuclear@2
|
34 PFNGLGETSHADERINFOLOGPROC gl_get_shader_info_log;
|
nuclear@2
|
35 PFNGLATTACHSHADERPROC gl_attach_shader;
|
nuclear@2
|
36 PFNGLLINKPROGRAMPROC gl_link_program;
|
nuclear@2
|
37 PFNGLGETPROGRAMIVPROC gl_get_programiv;
|
nuclear@2
|
38 PFNGLGETPROGRAMINFOLOGPROC gl_get_program_info_log;
|
nuclear@2
|
39 PFNGLUSEPROGRAMPROC gl_use_program;
|
nuclear@2
|
40 PFNGLGETUNIFORMLOCATIONPROC gl_get_uniform_location;
|
nuclear@2
|
41 PFNGLUNIFORM1IPROC gl_uniform1i;
|
nuclear@2
|
42 PFNGLUNIFORM2FPROC gl_uniform2f;
|
nuclear@2
|
43 PFNGLUNIFORMMATRIX4FVPROC gl_uniform_matrix4fv;
|
nuclear@2
|
44
|
nuclear@2
|
45 enum { FIT_FULL, FIT_CROP, FIT_STRETCH };
|
nuclear@2
|
46 static int fit_mode = FIT_FULL;
|
nuclear@2
|
47 static float crop_zoom = 1.0f;
|
nuclear@2
|
48 static float crop_dir[] = {0.0f, 0.0f};
|
nuclear@2
|
49
|
nuclear@2
|
50 static int tex_xsz, tex_ysz;
|
nuclear@2
|
51 static unsigned int img_tex, pal_tex, prog;
|
nuclear@2
|
52 static unsigned char pal[256 * 3];
|
nuclear@2
|
53 static int pal_valid;
|
nuclear@2
|
54
|
nuclear@2
|
55 static const char *vsdr =
|
nuclear@2
|
56 "uniform mat4 xform;\n"
|
nuclear@2
|
57 "uniform vec2 uvscale;\n"
|
nuclear@2
|
58 "varying vec2 uv;\n"
|
nuclear@2
|
59 "void main()\n"
|
nuclear@2
|
60 "{\n"
|
nuclear@2
|
61 "\tgl_Position = xform * gl_Vertex;\n"
|
nuclear@2
|
62 "\tuv = (gl_Vertex.xy * vec2(0.5, -0.5) + 0.5) * uvscale;\n"
|
nuclear@2
|
63 "}\n";
|
nuclear@2
|
64
|
nuclear@2
|
65 static const char *psdr =
|
nuclear@2
|
66 "uniform sampler2D img_tex;\n"
|
nuclear@2
|
67 "uniform sampler1D pal_tex;\n"
|
nuclear@2
|
68 "varying vec2 uv;\n"
|
nuclear@2
|
69 "void main()\n"
|
nuclear@2
|
70 "{\n"
|
nuclear@2
|
71 "\tfloat cidx = texture2D(img_tex, uv).x;\n"
|
nuclear@2
|
72 "\tvec3 color = texture1D(pal_tex, cidx).xyz;\n"
|
nuclear@2
|
73 "\tgl_FragColor.xyz = color;\n"
|
nuclear@2
|
74 "\tgl_FragColor.a = 1.0;\n"
|
nuclear@2
|
75 "}\n";
|
nuclear@2
|
76
|
nuclear@2
|
77 static int xform_loc, uvscale_loc;
|
nuclear@2
|
78
|
nuclear@2
|
79 void resize(int xsz, int ysz)
|
nuclear@2
|
80 {
|
nuclear@2
|
81 if(xsz == fbwidth && ysz == fbheight) return;
|
nuclear@2
|
82
|
nuclear@2
|
83 fbwidth = xsz;
|
nuclear@2
|
84 fbheight = ysz;
|
nuclear@2
|
85
|
nuclear@2
|
86 tex_xsz = next_pow2(fbwidth);
|
nuclear@2
|
87 tex_ysz = next_pow2(fbheight);
|
nuclear@2
|
88
|
nuclear@2
|
89 glBindTexture(GL_TEXTURE_2D, img_tex);
|
nuclear@2
|
90 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, tex_xsz, tex_ysz, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, 0);
|
nuclear@2
|
91 }
|
nuclear@2
|
92
|
nuclear@2
|
93
|
nuclear@2
|
94 void set_palette(int idx, int r, int g, int b)
|
nuclear@2
|
95 {
|
nuclear@2
|
96 unsigned char *pptr = pal + idx * 3;
|
nuclear@2
|
97 pptr[0] = r;
|
nuclear@2
|
98 pptr[1] = g;
|
nuclear@2
|
99 pptr[2] = b;
|
nuclear@2
|
100 pal_valid = 0;
|
nuclear@2
|
101 }
|
nuclear@2
|
102
|
nuclear@2
|
103 void colcycle_init(void)
|
nuclear@2
|
104 {
|
nuclear@2
|
105 int loc;
|
nuclear@2
|
106 char *argv[] = {"colcycle", "foo.lbm", 0};
|
nuclear@2
|
107
|
nuclear@2
|
108 init_glext();
|
nuclear@2
|
109
|
nuclear@2
|
110 fbwidth = 640;
|
nuclear@2
|
111 fbheight = 480;
|
nuclear@2
|
112 fbpixels = malloc(fbwidth * fbheight);
|
nuclear@2
|
113
|
nuclear@2
|
114 colc_init(2, argv);
|
nuclear@2
|
115
|
nuclear@2
|
116 tex_xsz = next_pow2(fbwidth);
|
nuclear@2
|
117 tex_ysz = next_pow2(fbheight);
|
nuclear@2
|
118
|
nuclear@2
|
119 glGenTextures(1, &img_tex);
|
nuclear@2
|
120 glBindTexture(GL_TEXTURE_2D, img_tex);
|
nuclear@2
|
121 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
nuclear@2
|
122 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
nuclear@2
|
123 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, tex_xsz, tex_ysz, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, 0);
|
nuclear@2
|
124 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, fbwidth, fbheight, GL_LUMINANCE, GL_UNSIGNED_BYTE, fbpixels);
|
nuclear@2
|
125
|
nuclear@2
|
126 glGenTextures(1, &pal_tex);
|
nuclear@2
|
127 glBindTexture(GL_TEXTURE_1D, pal_tex);
|
nuclear@2
|
128 glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
nuclear@2
|
129 glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
nuclear@2
|
130 glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
nuclear@2
|
131 glTexImage1D(GL_TEXTURE_1D, 0, GL_RGB, 256, 0, GL_RGB, GL_UNSIGNED_BYTE, pal);
|
nuclear@2
|
132
|
nuclear@2
|
133 if((prog = create_program(vsdr, psdr))) {
|
nuclear@2
|
134 gl_use_program(prog);
|
nuclear@2
|
135 if((loc = gl_get_uniform_location(prog, "img_tex")) >= 0) {
|
nuclear@2
|
136 gl_uniform1i(loc, 0);
|
nuclear@2
|
137 }
|
nuclear@2
|
138 if((loc = gl_get_uniform_location(prog, "pal_tex")) >= 0) {
|
nuclear@2
|
139 gl_uniform1i(loc, 1);
|
nuclear@2
|
140 }
|
nuclear@2
|
141 if((uvscale_loc = gl_get_uniform_location(prog, "uvscale")) >= 0) {
|
nuclear@2
|
142 gl_uniform2f(uvscale_loc, (float)fbwidth / (float)tex_xsz, (float)fbheight / (float)tex_ysz);
|
nuclear@2
|
143 }
|
nuclear@2
|
144 xform_loc = gl_get_uniform_location(prog, "xform");
|
nuclear@2
|
145 }
|
nuclear@2
|
146 gl_use_program(0);
|
nuclear@2
|
147
|
nuclear@2
|
148 if(enable_vsync() == -1) {
|
nuclear@2
|
149 fprintf(stderr, "failed to enable vsync\n");
|
nuclear@2
|
150 }
|
nuclear@2
|
151 }
|
nuclear@2
|
152
|
nuclear@2
|
153 void colcycle_cleanup(void)
|
nuclear@2
|
154 {
|
nuclear@2
|
155 colc_cleanup();
|
nuclear@2
|
156 }
|
nuclear@2
|
157
|
nuclear@2
|
158 void colcycle_draw(long time_msec)
|
nuclear@2
|
159 {
|
nuclear@2
|
160 float xform[16];
|
nuclear@2
|
161
|
nuclear@2
|
162 glClearColor(0, 0, 0, 1);
|
nuclear@2
|
163 glClear(GL_COLOR_BUFFER_BIT);
|
nuclear@2
|
164
|
nuclear@2
|
165 glViewport(0, 0, scr_width, scr_height);
|
nuclear@2
|
166
|
nuclear@2
|
167 calc_image_proj((float)fbwidth / (float)fbheight, xform);
|
nuclear@2
|
168
|
nuclear@2
|
169 gl_use_program(prog);
|
nuclear@2
|
170 if(xform_loc >= 0) {
|
nuclear@2
|
171 gl_uniform_matrix4fv(xform_loc, 1, GL_FALSE, xform);
|
nuclear@2
|
172 }
|
nuclear@2
|
173
|
nuclear@2
|
174 draw_screen(time_msec);
|
nuclear@2
|
175 }
|
nuclear@2
|
176
|
nuclear@2
|
177 static void draw_screen(long time_msec)
|
nuclear@2
|
178 {
|
nuclear@2
|
179 *(uint32_t*)fbpixels = 0xbadf00d;
|
nuclear@2
|
180 colc_draw(time_msec);
|
nuclear@2
|
181
|
nuclear@2
|
182 if(*(uint32_t*)fbpixels != 0xbadf00d) {
|
nuclear@2
|
183 /* update texture data if the framebuffer changed */
|
nuclear@2
|
184 glBindTexture(GL_TEXTURE_2D, img_tex);
|
nuclear@2
|
185 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, fbwidth, fbheight, GL_LUMINANCE, GL_UNSIGNED_BYTE, fbpixels);
|
nuclear@2
|
186 }
|
nuclear@2
|
187 if(!pal_valid) {
|
nuclear@2
|
188 /* update the palette texture */
|
nuclear@2
|
189 glBindTexture(GL_TEXTURE_1D, pal_tex);
|
nuclear@2
|
190 glTexSubImage1D(GL_TEXTURE_1D, 0, 0, 256, GL_RGB, GL_UNSIGNED_BYTE, pal);
|
nuclear@2
|
191 pal_valid = 1;
|
nuclear@2
|
192 }
|
nuclear@2
|
193
|
nuclear@2
|
194 gl_active_texture(GL_TEXTURE0);
|
nuclear@2
|
195 glBindTexture(GL_TEXTURE_2D, img_tex);
|
nuclear@2
|
196 gl_active_texture(GL_TEXTURE1);
|
nuclear@2
|
197 glBindTexture(GL_TEXTURE_1D, pal_tex);
|
nuclear@2
|
198 gl_active_texture(GL_TEXTURE0);
|
nuclear@2
|
199
|
nuclear@2
|
200 glBegin(GL_QUADS);
|
nuclear@2
|
201 glVertex2f(-1, -1);
|
nuclear@2
|
202 glVertex2f(1, -1);
|
nuclear@2
|
203 glVertex2f(1, 1);
|
nuclear@2
|
204 glVertex2f(-1, 1);
|
nuclear@2
|
205 glEnd();
|
nuclear@2
|
206
|
nuclear@2
|
207 assert(glGetError() == GL_NO_ERROR);
|
nuclear@2
|
208 }
|
nuclear@2
|
209
|
nuclear@2
|
210 static unsigned int create_program(const char *vsdr, const char *psdr)
|
nuclear@2
|
211 {
|
nuclear@2
|
212 unsigned int vs, ps, prog;
|
nuclear@2
|
213 int status, info_len;
|
nuclear@2
|
214
|
nuclear@2
|
215 if(!(vs = create_shader(GL_VERTEX_SHADER, vsdr))) {
|
nuclear@2
|
216 return 0;
|
nuclear@2
|
217 }
|
nuclear@2
|
218 if(!(ps = create_shader(GL_FRAGMENT_SHADER, psdr))) {
|
nuclear@2
|
219 gl_delete_shader(vs);
|
nuclear@2
|
220 return 0;
|
nuclear@2
|
221 }
|
nuclear@2
|
222
|
nuclear@2
|
223 prog = gl_create_program();
|
nuclear@2
|
224 gl_attach_shader(prog, vs);
|
nuclear@2
|
225 gl_attach_shader(prog, ps);
|
nuclear@2
|
226 gl_link_program(prog);
|
nuclear@2
|
227
|
nuclear@2
|
228 gl_get_programiv(prog, GL_LINK_STATUS, &status);
|
nuclear@2
|
229 if(!status) {
|
nuclear@2
|
230 fprintf(stderr, "failed to link shader program\n");
|
nuclear@2
|
231 gl_delete_program(prog);
|
nuclear@2
|
232 prog = 0;
|
nuclear@2
|
233 }
|
nuclear@2
|
234
|
nuclear@2
|
235 gl_get_programiv(prog, GL_INFO_LOG_LENGTH, &info_len);
|
nuclear@2
|
236 if(info_len) {
|
nuclear@2
|
237 char *buf = alloca(info_len + 1);
|
nuclear@2
|
238 gl_get_program_info_log(prog, info_len, 0, buf);
|
nuclear@2
|
239 buf[info_len] = 0;
|
nuclear@2
|
240 if(buf[0]) {
|
nuclear@2
|
241 fprintf(stderr, "linker output:\n%s\n", buf);
|
nuclear@2
|
242 }
|
nuclear@2
|
243 }
|
nuclear@2
|
244
|
nuclear@2
|
245 if(!status) {
|
nuclear@2
|
246 gl_delete_program(prog);
|
nuclear@2
|
247 prog = 0;
|
nuclear@2
|
248 }
|
nuclear@2
|
249 return prog;
|
nuclear@2
|
250 }
|
nuclear@2
|
251
|
nuclear@2
|
252 static unsigned int create_shader(unsigned int type, const char *src)
|
nuclear@2
|
253 {
|
nuclear@2
|
254 unsigned int sdr;
|
nuclear@2
|
255 int status, info_len;
|
nuclear@2
|
256
|
nuclear@2
|
257 sdr = gl_create_shader(type);
|
nuclear@2
|
258 gl_shader_source(sdr, 1, &src, 0);
|
nuclear@2
|
259 gl_compile_shader(sdr);
|
nuclear@2
|
260
|
nuclear@2
|
261 gl_get_shaderiv(sdr, GL_COMPILE_STATUS, &status);
|
nuclear@2
|
262 if(!status) {
|
nuclear@2
|
263 fprintf(stderr, "failed to compile %s shader\n", type == GL_VERTEX_SHADER ? "vertex" : "pixel");
|
nuclear@2
|
264 }
|
nuclear@2
|
265
|
nuclear@2
|
266 gl_get_shaderiv(sdr, GL_INFO_LOG_LENGTH, &info_len);
|
nuclear@2
|
267 if(info_len) {
|
nuclear@2
|
268 char *buf = alloca(info_len + 1);
|
nuclear@2
|
269 gl_get_shader_info_log(sdr, info_len, 0, buf);
|
nuclear@2
|
270 buf[info_len] = 0;
|
nuclear@2
|
271 if(buf[0]) {
|
nuclear@2
|
272 fprintf(stderr, "compiler output:\n%s\n", buf);
|
nuclear@2
|
273 }
|
nuclear@2
|
274 }
|
nuclear@2
|
275
|
nuclear@2
|
276 if(!status) {
|
nuclear@2
|
277 gl_delete_shader(sdr);
|
nuclear@2
|
278 sdr = 0;
|
nuclear@2
|
279 }
|
nuclear@2
|
280 return sdr;
|
nuclear@2
|
281 }
|
nuclear@2
|
282
|
nuclear@2
|
283 static unsigned int next_pow2(unsigned int x)
|
nuclear@2
|
284 {
|
nuclear@2
|
285 --x;
|
nuclear@2
|
286 x |= x >> 1;
|
nuclear@2
|
287 x |= x >> 2;
|
nuclear@2
|
288 x |= x >> 4;
|
nuclear@2
|
289 x |= x >> 8;
|
nuclear@2
|
290 x |= x >> 16;
|
nuclear@2
|
291 return x + 1;
|
nuclear@2
|
292 }
|
nuclear@2
|
293
|
nuclear@2
|
294 static int enable_vsync(void)
|
nuclear@2
|
295 {
|
nuclear@2
|
296 if(wgl_swap_interval) {
|
nuclear@2
|
297 wgl_swap_interval(1);
|
nuclear@2
|
298 }
|
nuclear@2
|
299 return -1;
|
nuclear@2
|
300 }
|
nuclear@2
|
301
|
nuclear@2
|
302 static int init_glext(void)
|
nuclear@2
|
303 {
|
nuclear@2
|
304 static int init_done;
|
nuclear@2
|
305 const char *extstr;
|
nuclear@2
|
306 PFNWGLGETEXTENSIONSSTRINGEXTPROC wgl_get_extstr_ext;
|
nuclear@2
|
307
|
nuclear@2
|
308 if(init_done) return 0;
|
nuclear@2
|
309 init_done = 1;
|
nuclear@2
|
310
|
nuclear@2
|
311 /* WGL extensions */
|
nuclear@2
|
312 if((wgl_get_extstr_ext = (PFNWGLGETEXTENSIONSSTRINGEXTPROC)wglGetProcAddress("wglGetExtensionsStringEXT"))) {
|
nuclear@2
|
313 if(!(extstr = wgl_get_extstr_ext())) {
|
nuclear@2
|
314 fprintf(stderr, "failed to retrieve WGL extensions string\n");
|
nuclear@2
|
315 return -1;
|
nuclear@2
|
316 }
|
nuclear@2
|
317 } else {
|
nuclear@2
|
318 fprintf(stderr, "wglGetExtensionsString not found\n");
|
nuclear@2
|
319 return -1;
|
nuclear@2
|
320 }
|
nuclear@2
|
321 if(strstr(extstr, "WGL_EXT_swap_control")) {
|
nuclear@2
|
322 wgl_swap_interval = (PFNWGLSWAPINTERVALEXTPROC)wglGetProcAddress("wglSwapIntervalEXT");
|
nuclear@2
|
323 }
|
nuclear@2
|
324
|
nuclear@2
|
325 /* OpenGL extensions */
|
nuclear@2
|
326 if(!(extstr = (const char*)glGetString(GL_EXTENSIONS))) {
|
nuclear@2
|
327 fprintf(stderr, "failed to retrieve GL extensions string\n");
|
nuclear@2
|
328 return -1;
|
nuclear@2
|
329 }
|
nuclear@2
|
330 /* proceed to ignore the extensions string and just attempt to load entry points,
|
nuclear@2
|
331 * because we want to use the GL2.0 style of the API, instead of the clunkier ARB one
|
nuclear@2
|
332 */
|
nuclear@2
|
333 if(!(gl_create_program = (PFNGLCREATEPROGRAMPROC)wglGetProcAddress("glCreateProgram"))) {
|
nuclear@2
|
334 fprintf(stderr, "failed to find the OpenGL shader API entry points\n");
|
nuclear@2
|
335 return -1;
|
nuclear@2
|
336 }
|
nuclear@2
|
337 /* assume everything else is there if glCreateProgram is there */
|
nuclear@2
|
338 gl_delete_program = (PFNGLDELETEPROGRAMPROC)wglGetProcAddress("glDeleteProgram");
|
nuclear@2
|
339 gl_create_shader = (PFNGLCREATESHADERPROC)wglGetProcAddress("glCreateShader");
|
nuclear@2
|
340 gl_delete_shader = (PFNGLDELETESHADERPROC)wglGetProcAddress("glDeleteShader");
|
nuclear@2
|
341 gl_shader_source = (PFNGLSHADERSOURCEPROC)wglGetProcAddress("glShaderSource");
|
nuclear@2
|
342 gl_compile_shader = (PFNGLCOMPILESHADERPROC)wglGetProcAddress("glCompileShader");
|
nuclear@2
|
343 gl_get_shaderiv = (PFNGLGETSHADERIVPROC)wglGetProcAddress("glGetShaderiv");
|
nuclear@2
|
344 gl_get_shader_info_log = (PFNGLGETSHADERINFOLOGPROC)wglGetProcAddress("glGetShaderInfoLog");
|
nuclear@2
|
345 gl_attach_shader = (PFNGLATTACHSHADERPROC)wglGetProcAddress("glAttachShader");
|
nuclear@2
|
346 gl_link_program = (PFNGLLINKPROGRAMPROC)wglGetProcAddress("glLinkProgram");
|
nuclear@2
|
347 gl_get_programiv = (PFNGLGETPROGRAMIVPROC)wglGetProcAddress("glGetProgramiv");
|
nuclear@2
|
348 gl_get_program_info_log = (PFNGLGETPROGRAMINFOLOGPROC)wglGetProcAddress("glGetProgramInfoLog");
|
nuclear@2
|
349 gl_use_program = (PFNGLUSEPROGRAMPROC)wglGetProcAddress("glUseProgram");
|
nuclear@2
|
350 gl_get_uniform_location = (PFNGLGETUNIFORMLOCATIONPROC)wglGetProcAddress("glGetUniformLocation");
|
nuclear@2
|
351 gl_uniform1i = (PFNGLUNIFORM1IPROC)wglGetProcAddress("glUniform1i");
|
nuclear@2
|
352 gl_uniform2f = (PFNGLUNIFORM2FPROC)wglGetProcAddress("glUniform2f");
|
nuclear@2
|
353 gl_uniform_matrix4fv = (PFNGLUNIFORMMATRIX4FVPROC)wglGetProcAddress("glUniformMatrix4fv");
|
nuclear@2
|
354
|
nuclear@2
|
355 if(!(gl_active_texture = (PFNGLACTIVETEXTUREPROC)wglGetProcAddress("glActiveTexture"))) {
|
nuclear@2
|
356 fprintf(stderr, "failed to find the multitexturing entry points\n");
|
nuclear@2
|
357 return -1;
|
nuclear@2
|
358 }
|
nuclear@2
|
359
|
nuclear@2
|
360 return 0;
|
nuclear@2
|
361 }
|
nuclear@2
|
362
|
nuclear@2
|
363 static void calc_image_proj(float img_aspect, float *xform)
|
nuclear@2
|
364 {
|
nuclear@2
|
365 static const float ident[] = {1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1};
|
nuclear@2
|
366 float vpscale;
|
nuclear@2
|
367 float aspect = (float)scr_width / (float)scr_height;
|
nuclear@2
|
368
|
nuclear@2
|
369 memcpy(xform, ident, sizeof ident);
|
nuclear@2
|
370
|
nuclear@2
|
371 if(fit_mode != FIT_STRETCH) {
|
nuclear@2
|
372 if(aspect > img_aspect) {
|
nuclear@2
|
373 vpscale = xform[0] = img_aspect / aspect;
|
nuclear@2
|
374 xform[5] = 1.0f;
|
nuclear@2
|
375 } else {
|
nuclear@2
|
376 vpscale = xform[5] = aspect / img_aspect;
|
nuclear@2
|
377 xform[0] = 1.0f;
|
nuclear@2
|
378 }
|
nuclear@2
|
379
|
nuclear@2
|
380 if(fit_mode == FIT_CROP) {
|
nuclear@2
|
381 float cropscale, maxpan, tx, ty;
|
nuclear@2
|
382
|
nuclear@2
|
383 cropscale = 1.0f / vpscale;
|
nuclear@2
|
384 cropscale = 1.0f + (cropscale - 1.0f) * crop_zoom;
|
nuclear@2
|
385 maxpan = cropscale - 1.0f;
|
nuclear@2
|
386
|
nuclear@2
|
387 xform[0] *= cropscale;
|
nuclear@2
|
388 xform[5] *= cropscale;
|
nuclear@2
|
389
|
nuclear@2
|
390 if(aspect > img_aspect) {
|
nuclear@2
|
391 tx = 0.0f;
|
nuclear@2
|
392 ty = -crop_dir[1] * maxpan;
|
nuclear@2
|
393 } else {
|
nuclear@2
|
394 tx = -crop_dir[0] * maxpan;
|
nuclear@2
|
395 ty = 0.0f;
|
nuclear@2
|
396 }
|
nuclear@2
|
397
|
nuclear@2
|
398 xform[12] = tx;
|
nuclear@2
|
399 xform[13] = ty;
|
nuclear@2
|
400 } else {
|
nuclear@2
|
401 xform[12] = xform[13] = 0.0f;
|
nuclear@2
|
402 }
|
nuclear@2
|
403 }
|
nuclear@2
|
404 }
|
nuclear@2
|
405
|