1using Fjord.Scenes;
2using System.Numerics;
3using System.Reflection.Metadata.Ecma335;
4using System.Runtime.InteropServices;
5using static SDL2.SDL;
6using static SDL2.SDL_image;
7
8namespace Fjord.Graphics;
9
10public interface IDrawInstruction {
11 public int depth { get; set; }
12}
13
14public struct Rectangle : IDrawInstruction {
15 public Vector4 rect;
16 public Vector4 color;
17 public float? borderRadius = null;
18 public bool fill;
19 public int depth { get; set; } = 0;
20
21 public Rectangle(Vector4 rect)
22 {
23 this.rect = rect;
24 }
25
26 public Rectangle Rect(Vector4 rect) {
27 this.rect = rect;
28 return this;
29 }
30
31 public Rectangle Color(Vector4 color) {
32 this.color = color;
33 return this;
34 }
35
36 public Rectangle Fill(bool fill)
37 {
38 this.fill = fill;
39 return this;
40 }
41
42 public Rectangle BorderRadius(float radius)
43 {
44 this.borderRadius = radius;
45 return this;
46 }
47
48 public Rectangle Depth(int depth)
49 {
50 this.depth = depth;
51 return this;
52 }
53
54 public void Render()
55 {
56 if (Draw.CurrentSceneID is not null)
57 {
58 SceneHandler.Scenes[Draw.CurrentSceneID].drawBuffer.Add(this);
59 }
60 else
61 {
62 Draw.drawBuffer.Add(this);
63 }
64 }
65
66 public Texture ToTexture()
67 {
68 IntPtr oldRender = SDL_GetRenderTarget(Game.SDLRenderer);
69
70 IntPtr tex = SDL_CreateTexture(Game.SDLRenderer, SDL_PIXELFORMAT_RGBA8888, (int)SDL_TextureAccess.SDL_TEXTUREACCESS_TARGET, (int)rect.Z, (int)rect.W);
71 SDL_SetTextureBlendMode(tex, SDL_BlendMode.SDL_BLENDMODE_BLEND);
72 SDL_SetRenderTarget(Game.SDLRenderer, tex);
73 var tempRect = this;
74 tempRect.rect.X = 0;
75 tempRect.rect.Y = 0;
76 Draw.RectangleDirect(tempRect);
77
78 SDL_SetRenderTarget(Game.SDLRenderer, oldRender);
79
80 var itex = new Texture(tex).Position(rect.X, rect.Y);
81
82 return itex;
83 }
84}
85
86public struct Circle : IDrawInstruction {
87 public Vector2 position;
88 public float radius;
89 public Vector4 color;
90 public CirlceAnimation? hoverAnimation;
91 public bool fill;
92
93 public Circle(Vector2 position, float radius)
94 {
95 this.position = position;
96 this.radius = radius;
97 }
98
99 public Circle Position(Vector2 position) {
100 this.position = position;
101 return this;
102 }
103
104 public Circle Radius(float radius) {
105 this.radius = radius;
106 return this;
107 }
108
109 public Circle Color(Vector4 color) {
110 this.color = color;
111 return this;
112 }
113
114 public Circle Fill(bool fill) {
115 this.fill = fill;
116 return this;
117 }
118
119 public Circle Depth(int depth)
120 {
121 this.depth = depth;
122 return this;
123 }
124
125 public Circle HoverAnimation(CirlceAnimation anim)
126 {
127 this.hoverAnimation = anim;
128 return this;
129 }
130
131 public void Render() {
132 if (Draw.CurrentSceneID is not null)
133 {
134 SceneHandler.Scenes[Draw.CurrentSceneID].drawBuffer.Add(this);
135 }
136 else
137 {
138 Draw.drawBuffer.Add(this);
139 }
140 }
141
142 public Texture ToTexture()
143 {
144 IntPtr oldRender = SDL_GetRenderTarget(Game.SDLRenderer);
145
146 IntPtr tex = SDL_CreateTexture(Game.SDLRenderer, SDL_PIXELFORMAT_RGBA8888, (int)SDL_TextureAccess.SDL_TEXTUREACCESS_TARGET, (int)(radius * 2 + 1), (int)(radius * 2 + 1));
147 if(color.W != 255)
148 SDL_SetTextureBlendMode(tex, SDL_BlendMode.SDL_BLENDMODE_BLEND);
149 SDL_SetRenderTarget(Game.SDLRenderer, tex);
150 SDL_SetRenderDrawColor(Game.SDLRenderer, 0, 0, 0, 0);
151 SDL_RenderClear(Game.SDLRenderer);
152
153 var tempRect = this;
154 tempRect.position.X = tempRect.radius;
155 tempRect.position.Y = tempRect.radius;
156 Draw.CircleDirect(tempRect);
157
158 SDL_SetRenderTarget(Game.SDLRenderer, oldRender);
159
160 var itex = new Texture(tex).Position(position.X, position.Y);
161
162 return itex;
163 }
164
165 public int depth { get; set; }
166}
167
168public class Texture : IDrawInstruction {
169 public Vector2 position;
170 public IntPtr SDLTexture;
171 public IntPtr SDLSurface;
172 public Vector2 textureSize;
173 public Vector2 sizeMultiplier = new(1, 1);
174 public bool destroy = false;
175 public float angle;
176 public Flip flip;
177 public float alpha = 255;
178 public Center center;
179 public bool isCustomCenter = false;
180 public Vector2 customCenter = new();
181 public Vector4? srcTextureOffset = null;
182
183 public Texture(string path)
184 {
185 path = path.OSPath();
186 if(!Draw.textureCache.ContainsKey(path)) {
187 if(File.Exists(path)) {
188 SDLSurface = IMG_Load(path);
189 SDLTexture = SDL_CreateTextureFromSurface(Game.SDLRenderer, SDLSurface);
190 Draw.textureCache.Add(path, SDLTexture);
191 } else {
192 throw new FileNotFoundException($"No image exists to load at path '{path}'");
193 }
194 } else {
195 SDLTexture = Draw.textureCache[path];
196 }
197 SDL_QueryTexture(SDLTexture, out uint format, out int access, out int w, out int h);
198 textureSize = new Vector2(w, h);
199 }
200
201 public Texture(IntPtr texture)
202 {
203 this.SDLTexture = texture;
204 SDL_QueryTexture(SDLTexture, out uint format, out int access, out int w, out int h);
205 textureSize = new Vector2(w, h);
206 }
207
208 public Texture SetTexture(IntPtr texture) {
209 this.SDLTexture = texture;
210 return this;
211 }
212
213 public Texture Position(Vector2 position) {
214 this.position = position;
215 return this;
216 }
217
218 public Texture Position(float x, float y) {
219 this.position = new(x, y);
220 return this;
221 }
222
223 public Texture PositionAndDepth(Vector2 position) {
224 this.position = position;
225 this.depth = -(int)position.Y;
226 return this;
227 }
228
229 public Texture PositionAndDepth(float x, float y) {
230 this.position = new(x, y);
231 this.depth = -(int)y;
232 return this;
233 }
234
235 public Texture Size(Vector2 size) {
236 this.textureSize = size;
237 return this;
238 }
239
240 public Texture Size(float w, float h) {
241 this.textureSize = new(w, h);
242 return this;
243 }
244 public Texture SizeMultiplier(Vector2 size)
245 {
246 this.sizeMultiplier = size;
247 return this;
248 }
249
250 public Texture SizeMultiplier(float w, float h)
251 {
252 this.sizeMultiplier = new(w, h);
253 return this;
254 }
255
256 public Texture Depth(int depth)
257 {
258 this.depth = depth;
259 return this;
260 }
261
262 public Texture Depth(float depth)
263 {
264 this.depth = (int)depth;
265 return this;
266 }
267
268 public Texture Depth(double depth)
269 {
270 this.depth = (int)depth;
271 return this;
272 }
273
274 public Texture Angle(float angle)
275 {
276 this.angle = angle;
277 return this;
278 }
279
280 public Texture Flip(Flip flip)
281 {
282 this.flip = flip;
283 return this;
284 }
285
286 public Texture Center(Center drawCenter)
287 {
288 this.center = drawCenter;
289 this.isCustomCenter = false;
290 return this;
291 }
292
293 public Texture Center(Vector2 drawCenter)
294 {
295 this.customCenter = drawCenter;
296 this.isCustomCenter = true;
297 return this;
298 }
299
300 public Texture Alpha(float alpha)
301 {
302 this.alpha = alpha;
303 return this;
304 }
305
306 public Texture Destroy(bool des)
307 {
308 this.destroy = des;
309 return this;
310 }
311
312 public Texture SrcTextureOffset(Vector4 off)
313 {
314 this.srcTextureOffset = off;
315 return this;
316 }
317
318 public Texture GetRect(out Vector4 outRect)
319 {
320 SDL_Rect rect = new()
321 {
322 x = (int)this.position.X,
323 y = (int)this.position.Y,
324 w = (int)(this.textureSize.X * this.sizeMultiplier.X),
325 h = (int)(this.textureSize.Y * this.sizeMultiplier.Y)
326 };
327
328 SDL_RendererFlip tmpFlip = this.flip == Graphics.Flip.Horizontal ? SDL_RendererFlip.SDL_FLIP_HORIZONTAL : this.flip == Graphics.Flip.Vertical ? SDL_RendererFlip.SDL_FLIP_VERTICAL : this.flip == Graphics.Flip.Both ? SDL_RendererFlip.SDL_FLIP_HORIZONTAL | SDL_RendererFlip.SDL_FLIP_VERTICAL : SDL_RendererFlip.SDL_FLIP_NONE;
329
330 Vector2 center = new();
331 Vector2 textureSize = this.textureSize;
332
333 if(!isCustomCenter)
334 {
335 switch (this.center)
336 {
337 case Graphics.Center.TopLeft:
338 {
339 center = new(0, 0);
340 }
341 break;
342 case Graphics.Center.TopMiddle:
343 {
344 center = new(rect.w / 2, 0);
345 }
346 break;
347 case Graphics.Center.TopRight:
348 {
349 center = new(rect.h, 0);
350 }
351 break;
352
353 case Graphics.Center.MiddleLeft:
354 {
355 center = new(0, rect.h / 2);
356 }
357 break;
358 case Graphics.Center.Middle:
359 {
360 center = new(rect.w / 2, rect.h / 2);
361 }
362 break;
363 case Graphics.Center.MiddleRight:
364 {
365 center = new(rect.w, rect.h / 2);
366 }
367 break;
368
369 case Graphics.Center.BottomLeft:
370 {
371 center = new(0, rect.h);
372 }
373 break;
374 case Graphics.Center.BottomMiddle:
375 {
376 center = new(rect.w / 2, rect.h);
377 }
378 break;
379 case Graphics.Center.BottomRight:
380 {
381 center = new(rect.w, rect.h);
382 }
383 break;
384 }
385 } else
386 {
387 center = new(customCenter.X, customCenter.Y);
388 }
389
390 SDL_Point sdlcenter = new()
391 {
392 x = (int)center.X,
393 y = (int)center.Y
394 };
395 rect.x -= sdlcenter.x;
396 rect.y -= sdlcenter.y;
397
398 outRect = new(rect.x, rect.y, rect.w, rect.h);
399
400 return this;
401 }
402
403 public Texture GetTextureAsSolid(Vector4 color)
404 {
405 // color = new(100, 100, 100, 255);
406 // IntPtr surface = SDL_CreateRGBSurface(0,(int)textureSize.X,(int)textureSize.Y,32,0,0,0,0);
407 // SDL_Rect dstRect = new();
408 // SDL_BlitSurface(SDLSurface, IntPtr.Zero, surface, ref dstRect);
409
410 // IntPtr newTexture = SDL_CreateTextureFromSurface(Game.SDLRenderer, surface);
411
412 IntPtr newTexture = SDL_CreateTexture(Game.SDLRenderer, SDL_PIXELFORMAT_RGBA8888, (int)SDL_TextureAccess.SDL_TEXTUREACCESS_TARGET, (int)textureSize.X, (int)textureSize.Y);
413
414 IntPtr oldRenderer = SDL_GetRenderer(Game.SDLRenderer);
415 SDL_SetRenderTarget(Game.SDLRenderer, newTexture);
416
417 SDL_RenderCopy(Game.SDLRenderer, SDLTexture, IntPtr.Zero, IntPtr.Zero);
418
419 SDL_SetRenderTarget(Game.SDLRenderer, oldRenderer);
420
421 SDL_SetTextureBlendMode(newTexture, SDL_BlendMode.SDL_BLENDMODE_BLEND);
422
423
424 SDL_SetTextureColorMod(newTexture, 0, 0, 0);
425 SDL_SetTextureAlphaMod(newTexture, 255);
426
427 SDL_SetTextureColorMod(newTexture, (byte)color.X, (byte)color.Y, (byte)color.Z);
428
429 return SetTexture(newTexture);
430 }
431
432 public void Render() {
433 if (Draw.CurrentSceneID is not null)
434 {
435 SceneHandler.Scenes[Draw.CurrentSceneID].drawBuffer.Add(this);
436 }
437 else
438 {
439 Draw.drawBuffer.Add(this);
440 }
441 }
442
443 public int depth { get; set; }
444}
445
446public struct Geometry : IDrawInstruction
447{
448 public List<SDL_Vertex> verticies = new List<SDL_Vertex>();
449
450 public Geometry()
451 {
452 }
453
454 public Geometry AddVertex(SDL_Vertex v)
455 {
456 verticies.Add(v);
457 return this;
458 }
459
460 public Geometry AddVertex(Vector2 position, Vector4 color, Vector2 tex_coord)
461 {
462 verticies.Add(new SDL_Vertex()
463 {
464 position = new SDL_FPoint() { x = position.X, y = position.Y },
465 color = new SDL_Color() { r = (byte)color.X, g = (byte)color.Y, b = (byte)color.Z, a = (byte)color.W },
466 tex_coord = new SDL_FPoint() { x = tex_coord.X, y = tex_coord.Y }
467 });
468 return this;
469 }
470 public Geometry AddVertex(Vector2 position, Vector4 color)
471 {
472 verticies.Add(new SDL_Vertex()
473 {
474 position = new SDL_FPoint() { x = position.X, y = position.Y },
475 color = new SDL_Color() { r = (byte)color.X, g = (byte)color.Y, b = (byte)color.Z, a = (byte)color.W },
476 tex_coord = new SDL_FPoint() { x = 0, y = 0 }
477 });
478 return this;
479 }
480
481 public Geometry Depth(int depth)
482 {
483 this.depth = depth;
484 return this;
485 }
486
487 public void Render()
488 {
489 if (Draw.CurrentSceneID is not null)
490 {
491 SceneHandler.Scenes[Draw.CurrentSceneID].drawBuffer.Add(this);
492 }
493 else
494 {
495 Draw.drawBuffer.Add(this);
496 }
497 }
498
499 public int depth { get; set; }
500}
501
502public struct Text : IDrawInstruction
503{
504 public string font;
505 public string value;
506 public Vector2 position;
507 public int size;
508 public Vector4 color;
509
510 public Text(string font, string text)
511 {
512 this.font = font;
513 this.value = text;
514 }
515
516 public Text(string text)
517 {
518 this.value = text;
519 this.font = Graphics.Font.DefaultFont;
520 }
521
522 public Text Font(string font)
523 {
524 this.font = font;
525 return this;
526 }
527
528 public Text Position(Vector2 position)
529 {
530 this.position = position;
531 return this;
532 }
533
534 public Text Position(float x, float y)
535 {
536 this.position = new(x, y);
537 return this;
538 }
539
540 public Text Size(int size)
541 {
542 this.size = size;
543 return this;
544 }
545
546 public Text Color(Vector4 color)
547 {
548 this.color = color;
549 return this;
550 }
551
552 public Text Color(SDL_Color color)
553 {
554 this.color = new(color.r, color.g, color.b, color.a);
555 return this;
556 }
557
558 public Text Depth(int depth)
559 {
560 this.depth = depth;
561 return this;
562 }
563
564 public void Render()
565 {
566 if (Draw.CurrentSceneID is not null)
567 {
568 SceneHandler.Scenes[Draw.CurrentSceneID].drawBuffer.Add(this);
569 }
570 else
571 {
572 Draw.drawBuffer.Add(this);
573 }
574 }
575
576 public Texture ToTexture()
577 {
578 IntPtr oldRender = SDL_GetRenderTarget(Game.SDLRenderer);
579
580 Vector2 size = Graphics.Font.DrawSize(font, value, this.size, color);
581
582 IntPtr tex = SDL_CreateTexture(Game.SDLRenderer, SDL_PIXELFORMAT_RGBA8888, (int)SDL_TextureAccess.SDL_TEXTUREACCESS_TARGET, (int)(size.X), (int)(size.Y));
583 SDL_SetTextureBlendMode(tex, SDL_BlendMode.SDL_BLENDMODE_BLEND);
584 SDL_SetRenderTarget(Game.SDLRenderer, tex);
585 SDL_SetRenderDrawColor(Game.SDLRenderer, 0, 0, 0, 0);
586 SDL_RenderClear(Game.SDLRenderer);
587 var tempRect = this;
588 tempRect.position.X = 0;
589 tempRect.position.Y = 0;
590 Draw.TextDirect(tempRect);
591
592 SDL_SetRenderTarget(Game.SDLRenderer, oldRender);
593
594 var itex = new Texture(tex).Position(position.X, position.Y);
595
596 return itex;
597 }
598
599 public int depth { get; set; }
600}
601
602public struct Line : IDrawInstruction
603{
604 public Vector2 point1 = new();
605 public Vector2 point2 = new();
606 public Vector4 color = new();
607
608 public Line(Vector2 point1, Vector2 point2)
609 {
610 this.point1 = point1;
611 this.point2 = point2;
612 }
613
614 public Line Color(Vector4 color)
615 {
616 this.color = color;
617 return this;
618 }
619
620 public Line Color(SDL_Color color)
621 {
622 this.color = new(color.r, color.g, color.b, color.a);
623 return this;
624 }
625
626 public Line Depth(int depth)
627 {
628 this.depth = depth;
629 return this;
630 }
631
632 public void Render()
633 {
634 if (Draw.CurrentSceneID is not null)
635 {
636 SceneHandler.Scenes[Draw.CurrentSceneID].drawBuffer.Add(this);
637 }
638 else
639 {
640 Draw.drawBuffer.Add(this);
641 }
642 }
643
644 public int depth { get; set; }
645}