1use std::convert::TryInto;
2use std::fmt::Debug;
3
4use crate::db_internal::{vdp_allocRenderTexture, vdp_allocTexture, vdp_bindTexture, vdp_bindTextureSlot, vdp_blendEquation, vdp_blendFunc, vdp_clearColor, vdp_clearDepth, vdp_copyFbToTexture, vdp_depthFunc, vdp_depthWrite, vdp_drawGeometry, vdp_drawGeometryPacked, vdp_getDepthQueryResult, vdp_getUsage, vdp_releaseTexture, vdp_setCulling, vdp_setRenderTarget, vdp_setSampleParams, vdp_setSampleParamsSlot, vdp_setTexCombine, vdp_setTextureData, vdp_setTextureDataRegion, vdp_setTextureDataYUV, vdp_setVUCData, vdp_setVULayout, vdp_setVUStride, vdp_setVsyncHandler, vdp_setWinding, vdp_submitDepthQuery, vdp_submitVU, vdp_uploadVUProgram, vdp_viewport};
5use crate::math::{Vector4, Vector2};
6
7static mut VSYNC_HANDLER: Option<fn()> = Option::None;
8
9#[repr(C)]
10#[derive(Clone, Copy)]
11pub struct Color32 {
12 pub r: u8,
13 pub g: u8,
14 pub b: u8,
15 pub a: u8,
16}
17
18impl Color32 {
19 pub const fn new(r: u8, g: u8, b: u8, a: u8) -> Color32 {
20 return Color32 { r: r, g: g, b: b, a: a };
21 }
22}
23
24#[repr(C)]
25#[derive(Clone, Copy)]
26pub struct Vertex {
27 pub position: Vector4,
28 pub color: Vector4,
29 pub ocolor: Vector4,
30 pub texcoord: Vector4,
31}
32
33impl Vertex {
34 pub const fn new(position: Vector4, color: Vector4, ocolor: Vector4, texcoord: Vector4) -> Vertex {
35 return Vertex { position: position, color: color, ocolor: ocolor, texcoord: texcoord };
36 }
37}
38
39#[repr(C)]
40#[derive(Clone, Copy)]
41pub struct PackedVertex {
42 pub position: Vector4,
43 pub texcoord: Vector2,
44 pub color: Color32,
45 pub ocolor: Color32,
46}
47
48impl PackedVertex {
49 pub const fn new(position: Vector4, texcoord: Vector2, color: Color32, ocolor: Color32) -> PackedVertex {
50 return PackedVertex { position: position, texcoord: texcoord, color: color, ocolor: ocolor };
51 }
52}
53
54#[repr(C)]
55#[derive(Clone, Copy)]
56pub struct Rectangle {
57 pub x: i32,
58 pub y: i32,
59 pub width: i32,
60 pub height: i32,
61}
62
63impl Rectangle {
64 pub const fn new(x: i32, y: i32, width: i32, height: i32) -> Rectangle {
65 return Rectangle { x: x, y: y, width: width, height: height };
66 }
67}
68
69#[derive(Clone, Copy, Debug)]
70pub enum TextureError {
71 DimensionsInvalid,
72 AllocationFailed
73}
74
75pub trait DBTex {
76 fn get_handle(self: &Self) -> i32;
77}
78
79#[repr(C)]
80pub struct Texture {
81 pub format: TextureFormat,
82 pub width: i32,
83 pub height: i32,
84 pub mipmap: bool,
85 handle: i32,
86}
87
88#[repr(C)]
89pub struct RenderTexture {
90 pub width: i32,
91 pub height: i32,
92 handle: i32,
93}
94
95impl DBTex for Texture {
96 fn get_handle(self: &Self) -> i32 {
97 self.handle
98 }
99}
100
101impl DBTex for RenderTexture {
102 fn get_handle(self: &Self) -> i32 {
103 self.handle
104 }
105}
106
107impl Texture {
108 pub fn new(width: i32, height: i32, mipmap: bool, format: TextureFormat) -> Result<Texture,TextureError> {
109 if format != TextureFormat::YUV420 && ((width & (width - 1)) != 0 || (height & (height - 1)) != 0) {
111 return Result::Err(TextureError::DimensionsInvalid);
112 }
113
114 let handle = unsafe { vdp_allocTexture(mipmap, format, width, height) };
116 if handle == -1 {
117 return Result::Err(TextureError::AllocationFailed);
118 }
119
120 return Result::Ok(Texture {
121 format: format,
122 mipmap: mipmap,
123 width: width,
124 height: height,
125 handle: handle
126 });
127 }
128
129 pub fn set_texture_data<T>(&self, level: i32, data: &[T]) {
131 unsafe {
132 let len_bytes = data.len() * size_of::<T>();
133 vdp_setTextureData(self.handle, level, data.as_ptr().cast(), len_bytes.try_into().unwrap());
134 }
135 }
136
137 pub fn set_texture_data_yuv(&self, y_data: &[u8], u_data: &[u8], v_data: &[u8]) {
139 unsafe {
140 vdp_setTextureDataYUV(self.handle,
141 y_data.as_ptr().cast(), y_data.len().try_into().unwrap(),
142 u_data.as_ptr().cast(), u_data.len().try_into().unwrap(),
143 v_data.as_ptr().cast(), v_data.len().try_into().unwrap());
144 }
145 }
146
147 pub fn set_texture_data_region<T>(&self, level: i32, dst_rect: Option<Rectangle>, data: &[T]) {
149 unsafe {
150 match dst_rect {
151 Some(v) => {
152 let len_bytes = data.len() * size_of::<T>();
153 vdp_setTextureDataRegion(self.handle, level, &v, data.as_ptr().cast(), len_bytes.try_into().unwrap());
154 }
155 None => {
156 vdp_setTextureData(self.handle, level, data.as_ptr().cast(), data.len().try_into().unwrap());
157 }
158 }
159 }
160 }
161
162 pub fn copy_framebuffer_to_texture(target: &Texture, src_rect: Rectangle, dst_rect: Rectangle) {
164 unsafe {
165 vdp_copyFbToTexture(&src_rect, &dst_rect, target.handle);
166 }
167 }
168}
169
170impl Drop for Texture {
171 fn drop(&mut self) {
172 unsafe { vdp_releaseTexture(self.handle) };
173 }
174}
175
176impl RenderTexture {
177 pub fn new(width: i32, height: i32) -> Result<RenderTexture,TextureError> {
178 if (width & (width - 1)) != 0 || (height & (height - 1)) != 0 {
180 return Result::Err(TextureError::DimensionsInvalid);
181 }
182
183 let handle = unsafe { vdp_allocRenderTexture(width, height) };
185 if handle == -1 {
186 return Result::Err(TextureError::AllocationFailed);
187 }
188
189 return Result::Ok(RenderTexture {
190 width: width,
191 height: height,
192 handle: handle
193 });
194 }
195}
196
197impl Drop for RenderTexture {
198 fn drop(&mut self) {
199 unsafe { vdp_releaseTexture(self.handle) };
200 }
201}
202
203#[repr(C)]
204#[derive(Clone, Copy)]
205pub enum Compare {
206 Never = 0x0200,
207 Less = 0x0201,
208 Equal = 0x0202,
209 LessOrEqual = 0x0203,
210 Greater = 0x0204,
211 NotEqual = 0x0205,
212 GreaterOrEqual = 0x0206,
213 Always = 0x0207,
214}
215
216#[repr(C)]
217#[derive(Clone, Copy)]
218pub enum BlendEquation {
219 Add = 0x8006,
220 Subtract = 0x800A,
221 ReverseSubtract = 0x800B,
222}
223
224#[repr(C)]
225#[derive(Clone, Copy)]
226pub enum BlendFactor {
227 Zero = 0,
228 One = 1,
229 SrcColor = 0x0300,
230 OneMinusSrcColor = 0x0301,
231 SrcAlpha = 0x0302,
232 OneMinusSrcAlpha = 0x0303,
233 DstAlpha = 0x0304,
234 OneMinusDstAlpha = 0x0305,
235 DstColor = 0x0306,
236 OneMinusDstColor = 0x0307,
237}
238
239#[repr(C)]
240#[derive(Clone, Copy)]
241pub enum WindingOrder {
242 Clockwise = 0x0900,
243 CounterClockwise = 0x0901,
244}
245
246#[repr(C)]
247#[derive(Clone, Copy)]
248pub enum Topology {
249 LineList = 0x0000,
250 LineStrip = 0x0001,
251 TriangleList = 0x0002,
252 TriangleStrip = 0x0003,
253}
254
255#[repr(C)]
256#[derive(Clone, Copy)]
257#[derive(PartialEq)]
258pub enum TextureFormat {
259 RGB565 = 0,
260 RGBA4444 = 1,
261 RGBA8888 = 2,
262 DXT1 = 3,
263 DXT3 = 4,
264 YUV420 = 5,
265}
266
267#[repr(C)]
268#[derive(Clone, Copy)]
269pub enum TextureFilter {
270 Nearest = 0x2600,
271 Linear = 0x2601,
272}
273
274#[repr(C)]
275#[derive(Clone, Copy)]
276pub enum TextureWrap {
277 Clamp = 0x812F,
278 Repeat = 0x2901,
279 Mirror = 0x8370,
280}
281
282#[repr(C)]
283#[derive(Clone, Copy)]
284#[derive(PartialEq)]
285pub enum VertexSlotFormat {
286 FLOAT1 = 0,
287 FLOAT2 = 1,
288 FLOAT3 = 2,
289 FLOAT4 = 3,
290 UNORM4 = 4,
291 SNORM4 = 5,
292}
293
294#[repr(C)]
295#[derive(Clone, Copy)]
296#[derive(PartialEq)]
297pub enum TexCombine {
298 None = 0,
299 Mul = 1,
300 Add = 2,
301 Sub = 3,
302 Mix = 4,
303 Dot3 = 5,
304}
305
306#[repr(C)]
307#[derive(Clone, Copy)]
308#[derive(PartialEq)]
309pub enum TextureUnit {
310 TU0 = 0,
311 TU1 = 1,
312}
313
314unsafe extern "C" fn real_vsync_handler() {
315 if let Some(handler) = VSYNC_HANDLER {
316 handler();
317 }
318}
319
320pub fn clear_color(color: Color32) {
322 unsafe { vdp_clearColor(&color); }
323}
324
325pub fn clear_depth(depth: f32) {
327 unsafe { vdp_clearDepth(depth); }
328}
329
330pub fn depth_write(enable: bool) {
332 unsafe { vdp_depthWrite(enable) };
333}
334
335pub fn depth_func(compare: Compare) {
337 unsafe { vdp_depthFunc(compare) };
338}
339
340pub fn blend_equation(mode: BlendEquation) {
342 unsafe { vdp_blendEquation(mode) };
343}
344
345pub fn blend_func(src_factor: BlendFactor, dst_factor: BlendFactor) {
347 unsafe { vdp_blendFunc(src_factor, dst_factor) };
348}
349
350pub fn set_winding(winding: WindingOrder) {
352 unsafe { vdp_setWinding(winding) };
353}
354
355pub fn set_culling(enabled: bool) {
357 unsafe { vdp_setCulling(enabled) };
358}
359
360#[deprecated(since = "0.1.16", note = "New apps should prefer a custom vertex layout in combination with submit_vu instead")]
362pub fn draw_geometry(topology: Topology, vertex_data: &[Vertex]) {
363 unsafe { vdp_drawGeometry(topology, 0, vertex_data.len().try_into().unwrap(), vertex_data.as_ptr()) };
364}
365
366#[deprecated(since = "0.1.16", note = "Use submit_vu instead")]
368pub fn draw_geometry_packed(topology: Topology, vertex_data: &[PackedVertex]) {
369 unsafe { vdp_drawGeometryPacked(topology, 0, vertex_data.len().try_into().unwrap(), vertex_data.as_ptr()) };
370}
371
372pub fn get_usage() -> i32 {
374 unsafe { return vdp_getUsage() };
375}
376
377#[deprecated(since = "0.1.16", note = "Use set_sample_params_slot instead")]
379pub fn set_sample_params(filter: TextureFilter, wrap_u: TextureWrap, wrap_v: TextureWrap) {
380 unsafe { vdp_setSampleParams(filter, wrap_u, wrap_v) };
381}
382
383#[deprecated(since = "0.1.16", note = "Use bind_texture_slot instead")]
385pub fn bind_texture(texture: Option<&Texture>) {
386 if texture.is_some() {
387 unsafe { vdp_bindTexture(texture.unwrap().handle) };
388 } else {
389 unsafe { vdp_bindTexture(-1) };
390 }
391}
392
393pub fn viewport(rect: Rectangle) {
395 unsafe {
396 vdp_viewport(rect.x, rect.y, rect.width, rect.height);
397 }
398}
399
400pub fn submit_depth_query(ref_val: f32, compare: Compare, rect: Rectangle) {
402 unsafe {
403 vdp_submitDepthQuery(ref_val, compare, rect.x, rect.y, rect.width, rect.height);
404 }
405}
406
407pub fn get_depth_query_result() -> i32 {
409 unsafe {
410 return vdp_getDepthQueryResult();
411 }
412}
413
414pub fn set_vu_cdata(offset: usize, data: &Vector4) {
416 unsafe {
417 vdp_setVUCData(offset as i32, (data as *const Vector4).cast());
418 }
419}
420
421pub fn set_vu_layout(slot: usize, offset: usize, format: VertexSlotFormat) {
423 unsafe {
424 vdp_setVULayout(slot as i32, offset as i32, format);
425 }
426}
427
428pub fn set_vu_stride(stride: usize) {
430 unsafe {
431 vdp_setVUStride(stride as i32);
432 }
433}
434
435pub fn upload_vu_program(program: &[u32]) {
437 unsafe {
438 let program_len = program.len() * 4;
439 vdp_uploadVUProgram(program.as_ptr().cast(), program_len as i32);
440 }
441}
442
443pub fn submit_vu<T>(topology: Topology, data: &[T]) {
445 unsafe {
446 let data_len = data.len() * size_of::<T>();
447 vdp_submitVU(topology, data.as_ptr().cast(), data_len as i32);
448 }
449}
450
451pub fn set_render_target(texture: Option<RenderTexture>) {
453 unsafe {
454 match texture {
455 Some(v) => {
456 vdp_setRenderTarget(v.handle);
457 }
458 None => {
459 vdp_setRenderTarget(-1);
460 }
461 }
462 }
463}
464
465pub fn set_sample_params_slot(slot: TextureUnit, filter: TextureFilter, wrap_u: TextureWrap, wrap_v: TextureWrap) {
467 unsafe {
468 vdp_setSampleParamsSlot(slot, filter, wrap_u, wrap_v);
469 }
470}
471
472pub fn bind_texture_slot<T: DBTex>(slot: TextureUnit, texture: Option<&T>) {
474 unsafe {
475 match texture {
476 Some(v) => {
477 vdp_bindTextureSlot(slot, v.get_handle());
478 }
479 None => {
480 vdp_bindTextureSlot(slot, -1);
481 }
482 }
483 }
484}
485
486pub fn set_tex_combine(tex_combine: TexCombine, vtx_combine: TexCombine) {
488 unsafe {
489 vdp_setTexCombine(tex_combine, vtx_combine);
490 }
491}
492
493pub fn set_vsync_handler(handler: Option<fn()>) {
495 unsafe {
496 VSYNC_HANDLER = handler;
497 vdp_setVsyncHandler(real_vsync_handler);
498 }
499}